Perché non usare più comandi con un || o && lavoro condizionale?


12

Funziona su un prompt della shell (bash, dash):

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

Tuttavia, sto provando a scrivere uno script di shell POSIX , inizia così:

#!/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 non so perché, ma non ricevo il messaggio :

L'argomento dato è vuoto.

se chiamo lo script in questo modo:

./test_empty_argument ""

Perché?


5
Vedi Come posso verificare se una variabile è vuota o contiene solo spazi? per verificare se una variabile è vuota, non impostata o contiene solo spazi. Il problema in questa domanda non ha nulla a che fare con quello.
ilkkachu,

1
Basta usareif [ X”” = X”$var” ] ; then echo isempty ; fi
user2497

3
@ user2497 Non c'è motivo di usarlo in nessuna shell rilasciata negli ultimi 20 anni. Questa è una soluzione alternativa per conchiglie vecchie e buggy.
Chepner,

@chepner Quindi non è una soluzione valida? Qualcos'altro deve essere usato?
user2497

6
[ "" = "$var" ]funzionerebbe benissimo; una stringa vuota tra virgolette non verrà rimossa dall'elenco degli argomenti di [. Ma non è nemmeno necessario, perché funziona [ -z "$var" ] anche bene.
Chepner

Risposte:


37

Nota che la tua linea

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

questo è lo stesso di

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

(un non quotato ;può, nella maggior parte dei casi, essere sostituito da un carattere di nuova riga)

Ciò significa che l' exit 1istruzione viene sempre eseguita indipendentemente dal numero di argomenti passati allo script. Questo a sua volta significa che il messaggio The given argument is empty.non avrebbe mai la possibilità di essere stampato.

Per eseguire più di una singola istruzione dopo un test utilizzando la "sintassi di cortocircuito", raggruppare le istruzioni in { ...; }. L'alternativa è usare ifun'istruzione corretta (che, IMHO, sembra più pulita in uno script):

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

Hai lo stesso problema con il tuo secondo test.


per quanto riguarda

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

Funzionerebbe per l'esempio dato, ma per il generico

some-test && command1 || command2

sarebbe non essere la stessa

if some-test; then
    command1
else
    command2
fi

Invece, è più simile

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

o

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

Cioè, se il test o il primo comando falliscono, viene eseguito il secondo comando, il che significa che ha il potenziale per eseguire tutte e tre le istruzioni coinvolte.


18

Questo:

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

non è:

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

Ma invece è:

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

Il tuo script sta uscendo indipendentemente dal numero di argomenti che gli hai passato.


8

Un modo per renderlo più leggibile è definire una diefunzione (à la perl) come:

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

# then:

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

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

Puoi aggiungere più campane e fischietti come colori, prefisso, numero di riga ... se necessario.


In pratica, hai mai chiamato la tua diefunzione con più argomenti? (Se è così, puoi fare un esempio?) Uso una diefunzione quasi identica , ma uso "$*"invece, che potrebbe essere più ciò che intendi?
jrw32982 supporta Monica

3
Il valore di "$@"è che consente messaggi a più righe senza la necessità di aggiungere nuove righe letterali.
Charles Duffy,

1
@ jrw32982, l'utilizzo "$*"di join args con spazi significa anche che è necessario impostare $IFSSPC affinché funzioni in tutti i contesti, inclusi quelli in cui $IFSè stato modificato. In alternativa con ksh/ zsh, puoi usare print -r -- "$@"o echo -E - "$@"dentro zsh.
Stéphane Chazelas,

@CharlesDuffy Sì, ma non l'ho mai visto nel contesto di una diefunzione di tipo. Quello che sto chiedendo è: in pratica, hai mai visto qualcuno scrivere die "unable to blah:" "some error", allo scopo di ottenere un messaggio di errore a 2 righe?
jrw32982 supporta Monica

@ StéphaneChazelas Buon punto. Quindi (nella mia formulazione) dovrebbe essere die() { IFS=" "; printf >&2 "%s\n" "$*"; exit 1; }. Hai mai usato personalmente questo tipo di diefunzione per printfgenerare un messaggio di errore su più righe passando più argomenti? O passi mai solo un singolo argomento in diemodo che aggiunga solo una nuova riga al suo output?
jrw32982 supporta Monica

-1

L'ho visto spesso come un test per una stringa vuota:

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

Avrebbe dovuto essere "=" - risolto.
wef

3
Questa pratica è letteralmente degli anni '70. Non v'è alcun motivo per usarlo con qualsiasi guscio che è compatibile con lo standard POSIX sh 1992 (purché corretto citare viene utilizzato e funzionalità ormai obsoleti quali -a, -o, (e )come derectives a dire testper combinare più operazioni in una singola invocazione sono evitati; consultare i marker OB in pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html ).
Charles Duffy,

Unices non Linux distribuiti con l'originale "sh" negli anni '90 - forse lo fanno ancora. Nel mio lavoro a quel tempo, dovevo scrivere script di installazione portatili e ho usato questo costrutto. Ho appena esaminato gli script di installazione forniti da NVidia per Linux e usano ancora questo costrutto.
wef

NVidia può usarlo, ma ciò non significa che abbiano alcuna giustificazione tecnica per farlo; lo sviluppo commerciale di merci in UNIX commerciale è purtroppo prevalente. Anche Heirloom Bourne non ha il bug in questione, quindi neanche la base di codice SunOS (che è l'ultimo UNIX commerciale a spedire un non-POSIX /bin/sh, e il predecessore immediato di Heirloom Bourne).
Charles Duffy,

1
Non indosso un cappello, quindi non posso promettere di pubblicare un video di YouTube che lo mangia se qualcuno dovesse alzare una shell pubblicata su un UNIX commerciale con questo bug post-1990 ... ma se lo facessi, sarebbe allettante . :)
Charles Duffy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.