Captura "comando não encontrado" do shell script

5

Eu tenho um script de shell

echo "Type your command"
read command
echo "You typed $command"
$command

então é simples, roda um comando. Minha pergunta é se a entrada está errada suponha que lw o terminal diga command not found então como eu posso recuperar essa informação para o meu shell script e imprimir no terminal Try again wrong command . Eu tenho que redirecionar a saída do comando para um determinado arquivo e ler ou há algum tipo de sinal de interceptação que é passado para o meu script.Qual é o seu conselho sobre como fazer isso da maneira mais eficiente.

    
por Phil_Charly 10.12.2013 / 18:09

3 respostas

7

Quando um comando não é encontrado, o status de saída é 127. Você poderia usá-lo para determinar que o comando não foi encontrado:

until
  printf "Enter a command: "
  read command
  "$command"
  [ "$?" -ne 127 ]
do
  echo Try again
done

Embora os comandos geralmente não retornem um status de saída 127 (no caso em que entraria em conflito com o valor especial padrão usado pelos shells), há alguns casos em que um comando pode retornar genuinamente um status de saída 127: um script cujo último comando não pode ser encontrado.

bash e zsh tem uma função especial command_not_found_handler (há um erro de digitação em bash como é chamado command_not_found_handle ), que quando definido é executado quando um comando não é encontrado. Mas ele é executado em um contexto de subshell e também pode ser executado em comandos não encontrados durante a execução de uma função.

Você pode ficar tentado a verificar previamente a existência do comando usando type ou command -v , mas cuidado:

"$commands"

é analisado como um simples comando e os aliases não são expandidos, enquanto type ou command retornaria true também para aliases e palavras-chave shell.

Por exemplo, com command=for , type -- "$command" retornaria true, mas "$command" retornaria (muito provavelmente) um erro comando não encontrado .

which pode falhar por vários outros motivos.

O ideal é que você queira algo que retorne verdadeiro se o comando existir como uma função, um shell interno ou um comando externo.

hash atenderia a esses critérios pelo menos para ash e bash (não yash nem ksh nem zsh ). Então, isso funcionaria em bash ou ash :

while
  printf "Enter a command: "
  read command
do
  if hash -- "$command" 2> /dev/null; then
    "$command"
    break
  fi
  echo Try again
done

Um problema com isso é que hash retorna true também para um diretório (para um caminho para um diretório incluindo / ). Enquanto se você tentar executá-lo, enquanto ele não retornar um erro comando não encontrado , ele retornará um erro Is a directory ou Permission Denied . Se você quiser cobrir isso, você poderia fazer:

while
  printf "Enter a command: "
  read command
do
  if hash -- "$command" 2> /dev/null &&
     { [ "${command#*/}" != "$command" ] || [ ! -d "$command" ];}
  then
    "$command"
    break
  fi
  echo Try again
done
    
por 10.12.2013 / 22:51
4
  • trap é somente para sinais, que são definidos em signal(7) . Não encontrar um comando é simplesmente uma falha na família de funções exec , que retornará -1 , e não enviará um sinal.
  • Uma maneira melhor de capturar comandos inexistentes seria fazer algo assim.

    if ! type "$command" >/dev/null 2>&1; then
        echo "Try again, wrong command" 1>&2 # should output to stderr, not stdout
    else
        "$command"
    fi
    
por 10.12.2013 / 18:19
1

Aqui está uma outra maneira que usa o código de Stéphane Chazelas, mas com type , e supera as limitações de type ...

function isCommand () {
  #
  local _arg=" $(type -t "$1") "
  local _executables=' file alias keyword function builtin '
  #
  [[ "${_executables#*$_arg}" != "$_executables" ]]  && return 0
  ### if $_arg is NOT in $_executables, the two strings will be identical
  #
  return 1
}

while
  printf "Enter a command: "
  read command
do
  isCommand "$command"  && { "$command"; break; }
  #
  echo Try again
done

Notas

  • em isCommand () ...
    • ... as variáveis são preenchidas para evitar correspondências parciais.
    • ... type retorna "arquivo" para qualquer arquivo com o bit de execução definido. É assim que detectamos comandos externos.
    • ... este teste para inclusão em uma string é um dos mais não intuitivos que eu conheço. Mas é rápido e não usa comandos externos, então eu uso e envolvo uma função mais intuitiva em torno dele. Existem várias outras maneiras de fazer isso também.
  • isCommand "$command" && { "$command"; break; }
    Isso usa uma lista de comandos para a lógica de execução if-then. (veja bash manpage em Shell Grammer, Lists )
    • Vantagens
      • ... execução mais rápida que o% normalif[[...]] construct
      • ... evita lógica de vários testes complicada (e propensa a erros)
      • ... semelhante a OOP try/catch tratamento de exceções
    • Advertência
      • ... Na parte "then" após o && ou || , vários comandos devem ser colocados entre chaves e o último comando e seus argumentos devem ser terminados com um ponto-e-vírgula ; como em { cmd1 args; cmd2 args; } .
por 21.01.2016 / 04:10