Essa é uma maneira incorreta de escrever:
#!/bin/sh -
set -e # Exit if any command fails
# If multiple args given run this script once for each arg
if [ "$#" -gt 1 ]; then
for arg do
"$0" "$arg"
done
exit
fi
Acho que o que o autor pretendia fazer era verificar se o segundo argumento era uma string não vazia (o que não é a mesma coisa que verificar se há mais de 1 argumento, já que o segundo argumento poderia ser passado, mas seria o corda vazia).
test somestring
Uma forma abreviada de
test -n somestring
Retorna true se somestring
não for a string vazia. ( test ''
retorna falso, test anythingelse
retorna verdadeiro (mas cuidado com test -t
em alguns shells que verificam se stdout é um terminal)).
No entanto, o autor esqueceu as aspas em torno da variável (em todas as variáveis, na verdade). O que isso significa é que o conteúdo de $2
está sujeito ao operador split + glob. Portanto, se $2
contiver caracteres de $IFS
(espaço, guia e nova linha por padrão) ou caracteres glob ( *
, ?
, [...]
), isso não funcionará corretamente.
E se $2
estiver vazio (como quando menos de dois argumentos forem passados ou o segundo argumento estiver vazio), test $2
se tornará test
, não test ''
. test
não recebe nenhum argumento (vazio ou não).
Felizmente, nesse caso, test
sem argumentos retorna false. É um pouco melhor que test -n $2
, o que teria retornado true (já que se tornaria test -n
, igual a test -n -n
), de modo que o código pareceria funcionar em alguns casos.
Para resumir:
-
para testar se 2 ou mais argumentos são passados:
[ "$#" -gt 1 ]
ou
[ "$#" -ge 2 ]
-
para testar se uma variável não está vazia:
[ -n "$var" ] [ "$var" != '' ] [ "$var" ]
todos os quais são confiáveis em implementações POSIX de
[
, mas se você tiver que lidar com sistemas muito antigos, você pode ter que usar[ '' != "$var" ]
em vez de implementações de
[
que se sufocam em valores de$var
como=
,-t
,(
... -
para testar se uma variável está definida (que pode ser usada para testar se o script recebe um segundo argumento, mas usar
$#
é muito mais fácil de ler e mais idiomático):[ "${var+defined}" = defined ]
(ou o equivalente com a forma test
. Usar o alias [
para o comando test
é mais comum).
Agora, a diferença entre cmd1 && cmd2
e if cmd1; then cmd2; fi
.
Ambos executam cmd2
apenas se cmd1
for bem-sucedido. A diferença nesse caso é que o status de saída da lista geral de comandos será o do último comando executado no caso &&
(portanto, um código falha se cmd1
não for return true (embora isso não atropele set -e
aqui)) enquanto no caso if
, isso será o de cmd2
ou 0 (sucesso) se cmd2
não for executado.
Portanto, nos casos em que cmd1
deve ser usado como uma condição (quando sua falha não deve ser considerada como um problema ), geralmente é melhor usar if
, especialmente se for a última coisa que você faz em um script, pois isso definirá o status de saída do seu script. Também faz um código mais legível.
A forma cmd1 && cmd2
é mais comumente usada como condições , como em:
if cmd1 && cmd2; then...
while cmd1 && cmd2; do...
Isso ocorre em contextos em que nos preocupamos com o status de saída desses dois comandos.