Por que não usar vários comandos com um || ou && trabalho condicional?


12

Isso funciona em um prompt do shell (bash, dash):

[ -z "" ] && echo A || echo B
A

No entanto, estou tentando escrever um script de shell POSIX , que começa assim:

#!/bin/sh

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

readonly raw_input_string=${1}

[ -z "${raw_input_string}" ] && echo "The given argument is empty."; exit 1

E não sei por que, mas não recebo a mensagem :

O argumento fornecido está vazio.

se eu chamar o script assim:

./test_empty_argument ""

Por que é que?


5
Consulte Como posso testar se uma variável está vazia ou contém apenas espaços? para saber como testar se uma variável está vazia, não configurada ou contém apenas espaços em branco. O problema nesta pergunta não tem nada a ver com isso.
Ilkkachu

1
Uso apenasif [ X”” = X”$var” ] ; then echo isempty ; fi
user2497

3
@ user2497 Não há razão para usá-lo em qualquer shell lançado nos últimos 20 anos. Essa é uma solução alternativa para conchas antigas de buggy.
Chepner #

@chepner Portanto, não é uma solução válida? Algo mais deve ser usado?
precisa saber é o seguinte

6
[ "" = "$var" ]funcionaria bem; uma string vazia entre aspas não será removida da lista de argumentos de [. Mas isso também não é necessário, porque [ -z "$var" ] também funciona muito bem.
Chepner #

Respostas:


37

Observe que sua linha

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

isso é o mesmo que

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."
exit 1

(um não citado ;pode, na maioria das circunstâncias, ser substituído por um caractere de nova linha)

Isso significa que a exit 1instrução é sempre executada, independentemente de quantos argumentos foram passados ​​para o script. Por sua vez, isso significa que a mensagem The given argument is empty.nunca teria a chance de ser impressa.

Para executar mais de uma única instrução após um teste usando a "sintaxe de curto-circuito", agrupe as instruções em { ...; }. A alternativa é usar uma ifdeclaração adequada (que, IMHO, parece mais limpa em um script):

if [ "$#" -ne 1 ]; then
    echo 'Invalid number of arguments, expected one.' >&2
    exit 1
fi

Você tem o mesmo problema com seu segundo teste.


A respeito de

[ -z "" ] && echo A || echo B

Isso funcionaria para o exemplo dado, mas o genérico

some-test && command1 || command2

seria não ser o mesmo que

if some-test; then
    command1
else
    command2
fi

Em vez disso, é mais como

if ! { some-test && command1; }; then
    command2
fi

ou

if some-test && command1; then
    :
else
    command2
fi

Ou seja, se o teste ou o primeiro comando falhar, o segundo comando será executado, o que significa que ele tem o potencial de executar todas as três instruções envolvidas.


18

Este:

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

não é:

[ "${#}" -eq 1 ] || { echo "Invalid number of arguments, expected one."; exit 1; }

Mas em vez disso é:

{ [ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; } 
exit 1

Seu script está saindo, independentemente de quantos argumentos você passou para ele.


8

Uma maneira de torná-lo mais legível é definir uma diefunção (à la perl) como:

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

# then:

[ "$#" -eq 1 ] || die "Expected one argument, got $#"

[ -n "$1" ] || die "Empty argument not supported"

Você pode adicionar mais sinos e assobios, como cores, prefixo, número da linha ... se necessário.


Na prática, você chama sua diefunção com vários argumentos? (Se sim, você pode dar um exemplo?) Eu uso uma diefunção quase idêntica , mas em "$*"vez disso, qual pode ser mais o que você pretende?
Jrw32982 suporta Monica

3
O valor de "$@"é que ele permite mensagens de várias linhas sem a necessidade de adicionar novas linhas literais.
Charles Duffy #

1
@ jrw32982, usar "$*"para associar argumentos a espaços também significa que você precisa definir o $IFSSPC para que ele funcione em todos os contextos, incluindo aqueles onde $IFSforam modificados. Como alternativa com ksh/ zsh, você pode usar print -r -- "$@"ou echo -E - "$@"em zsh.
Stéphane Chazelas 4/04/19

@CharlesDuffy Sim, mas nunca vi isso feito no contexto de uma diefunção -type. O que estou perguntando é: na prática, você já viu alguém escrever die "unable to blah:" "some error", com o objetivo de receber uma mensagem de erro de duas linhas?
jrw32982 suporta Monica

@ StéphaneChazelas Bom ponto. Então (na minha formulação) deveria ser die() { IFS=" "; printf >&2 "%s\n" "$*"; exit 1; }. Você já usou pessoalmente esse tipo de diefunção para printfgerar uma mensagem de erro de várias linhas passando vários argumentos? Ou você apenas passa um único argumento para dieque ele adicione apenas uma nova linha à saída?
Jrw32982 suporta Monica

-1

Eu sempre vi isso como um teste para uma string vazia:

if [ "x$foo" = "x" ]; then ...

Deveria ter sido "=" - corrigido.
Wef

3
Essa prática é literalmente da década de 1970. Não há razão para usá-lo com qualquer shell que seja compatível com o POSIX padrão sh 1992 (desde que correta citando é usado e funcionalidade agora obsoleta, como -a, -o, (e )como derectives para contar testpara combinar várias operações em uma única invocação são evitados; consulte os marcadores OB em pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html ).
Charles Duffy #

As unidades não-linux enviadas com o 'sh' original até os anos 90 - talvez ainda o façam. No meu trabalho naquela época, tive que escrever scripts de instalação portáteis e usei essa construção. Eu apenas observei os scripts de instalação que a NVidia envia para Linux e eles ainda usam essa construção.
wef

A NVidia pode usá-lo, mas isso não significa que eles tenham alguma justificativa técnica para fazê-lo; o desenvolvimento do culto à carga no UNIX comercial é tristemente prevalente. Mesmo o Heirloom Bourne não tem o bug em questão - então a base de código do SunOS (que foi o último UNIX comercial a lançar um não-POSIX /bin/she o antecessor imediato do Heirloom Bourne) também não o tinha.
Charles Duffy

1
Eu não uso chapéu, por isso não posso prometer postar um vídeo do YouTube, caso alguém apareça em um shell publicado em um UNIX comercial com esse bug pós-1990 ... mas se eu usasse, seria tentador . :)
Charles Duffy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.