Usando $? em uma declaração if

7
function foo {
   (cd $FOOBAR;
   <some command>
   if [$? -ne 0]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

Eu estou tentando escrever uma função como a acima e colocá-la no meu arquivo .bashrc. Depois de fornecer o arquivo e executá-lo, obtenho:

Total time: 51 seconds
-bash: [1: command not found
OK!

Alguém pode me ajudar a entender o que eu fiz de errado?

    
por Amir Afghani 04.02.2014 / 23:07

5 respostas

30

Adicione um espaço após o [ e outro antes do ] :

function foo {
   (cd $FOOBAR;
   <some command>
   if [ $? -ne 0 ]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

[ é um shell embutido, é um comando como echo , read , expr ... ele precisa de um espaço depois dele e requer um ] correspondente.

A gravação de [ $? -ne 0 ] está realmente invocando [ e fornecendo quatro parâmetros: $? , -ne , 0 e ] .

Observação: o fato de você estar recebendo um erro dizendo [1: command not found significa que $? estava tendo o valor de 1 .

    
por 04.02.2014 / 23:10
19

Ou você pode pular $? ao todo. Se o seu comando for cmd , o seguinte deverá funcionar:

function foo {
   (cd $FOOBAR;
   if cmd
   then
      echo "OK!"
   else
      echo "Nope!"
   fi
   )
}
    
por 04.02.2014 / 23:22
6

É uma boa prática atribuir o valor de retorno a uma variável antes de usá-la

retval="$?"
if [ $retval -ne 0 ]

Permite-lhe reutilizar o valor de retorno. por exemplo. em uma declaração if ... elif ... else ...

    
por 04.02.2014 / 23:12
3

A única razão pela qual você desejaria usar $? como argumentos para um comando [ (se o comando [ é executado na condição parte de uma instrução if ou não) é quando você deseja para discriminar um status de retorno específico, como:

until
  cmd
  [ "$?" -gt 1 ]
do
  something
done

A sintaxe para todas as instruções if , while , until ... é

if cmd-list1
then cmd-list2
else cmd-list3
fi

Que executa cmd-list2 se cmd-list1 for bem-sucedida ou cmd-list3 caso contrário.

O comando [ "$?" -eq 0 ] é um não operacional. Define $? para 0 se $? for 0 e $? para diferente de zero se não for zero.

Se você quiser executar algo se cmd falhar, é:

if ! cmd
then ...
fi

Geralmente, você não precisa mexer com $? e muito menos saber qual valor significa true ou false . Os únicos casos são como eu disse acima, se você precisa discriminar um valor específico, ou se você precisa salvá-lo para mais tarde (por exemplo, retorná-lo como o valor de retorno de uma função) como:

f() {
  cmd; ret=$?
  some cleanup
  return "$ret"
}

Lembre-se também de que deixar uma variável sem aspas é o operador split + glob. Não faz sentido invocar esse operador aqui, então deve ser:

[ "$?" -ne 0 ]

não [ $? -ne 0 ] , e muito menos [$? -ne 0 ] (que só invocaria o comando [ se $IFS contivesse o primeiro caractere de $? ).

Observe também que a maneira Bourne de definir uma função é colocar function-name() na frente de um comando. Esse é o caso em todos os shell Bourne, exceto bash e yash (e versões recentes de posh ) que permitem apenas um comando composto (comandos compostos sendo {...} ou (...) ou coisas como for...done , if...fi ...

function foo { ... } é a sintaxe da definição da função ksh . Não há motivos para usar aqui.

Seu código pode ser portável (POSIXly) escrito:

foo() (
  cd -P -- "$FOOBAR" || return # what if the cd failed!
  if
    <some command>
  then
    echo 'OK!'
  else
    echo 'Nope!'
  fi
)

Observe também que cd sem -P tem um significado muito especial (lida com caminhos que contêm .. componentes diferentemente de qualquer outro comando), por isso é melhor incluí-lo em scripts para evitar confusões.

(essa função retorna false se cd falhar, mas não se <some command> falhar).

    
por 05.02.2014 / 12:53
1

Eu acredito que o comando abaixo fará tudo o que você quiser em uma linha.

(( verify = $?!=0?'Nope!':'OK!' ))
    
por 05.02.2014 / 17:16