Qual è l'equivalente di && quando si scrive uno script bash?


31

Mi scuso in anticipo se questa è una domanda duplicata. Ho fatto uno sforzo per cercare / controllare prima di chiedere qui.

Sono a mio agio con la scrittura di una riga come questa:

foocommand && foocommand2 && foocommand3

L'idea è che voglio solo i successivi comandi da eseguire se il precedente ha avuto successo.

Sto scrivendo una sceneggiatura piuttosto lunga e questo one-liner non è fattibile perché sembra un enorme blocco di codice confuso per tutti gli altri.

Voglio spaziare i comandi e scrivere commenti tra loro nello script. Come posso fare questo e avere ancora l'equivalente di && lì dentro?


4
Questa la pena ripeterlo: &&non significa che il comando successivo verrà eseguito se il precedente uno ha avuto successo. Significa che il comando verrà eseguito se il risultato collettivo di tutti i comandi precedenti nell'elenco dei comandi ha esito positivo. Potresti saperlo, ma i futuri lettori potrebbero fraintendere.
— Kojiro,

1
Inoltre, come nota, questo comportamento che stai descrivendo proviene ||e &&(al contrario di |o &) è chiamato corto circuito. Il comportamento usato con questi ultimi operatori è chiamato valutazione desiderosa.
— AndyPerfect,

7
@kojiro: non vedo la distinzione. a && b && cverrà eseguito solo in bcaso di asuccesso, quindi "funziona solo cse briesce" e "funziona solo cse aed bentrambi hanno successo" sono istruzioni equivalenti: bnon possono avere successo se non ci sono ariuscite.
— Ruakh,

1
@ruakh a || b && cè più illustrativo.
— Kojiro,

8
@ruakh no, true || false && echo hiverrà emesso hi. La specifica recita, Gli operatori "&&" e "||" deve avere la stessa precedenza e deve essere valutato con associatività di sinistra.
— Kojiro,

Risposte:


23

Puoi farlo in questo modo:

#!/bin/sh
ls -lh &&
    # This is a comment
    echo 'Wicked, it works!'

Spero di aver capito cosa hai chiesto correttamente.


Grazie. Questo è il più vicino a quello che speravo di fare. E rende molto semplice la riconversione in una fodera, se necessario.
— Mike B,

Mike, dato che sei preoccupato per la pulizia del codice, una convenzione comune è quella di rientrare nelle sezioni 2-N della catena sotto la prima.
— jblaine,

@jblaine Non sono sicuro di aver capito cosa intendi. Puoi per favore elaborare?
— Mike B,

Mike, Stackexchange non mi consente di formattare correttamente la mia risposta, quindi ecco tutto ciò che intendevo: indent
— jblaine,

@jblaine Buon punto, modificato per rientrare nelle righe.
— Volker Siegel,

38

Puoi cambiare la linea di shebang in

#!/bin/bash -e

Dopo qualsiasi errore, lo script si interromperà.


1
Interessante. Lo terro 'a mente. Grazie.
— Mike B,

mi salva dal digitare set -e quando ne ho bisogno
— Silverrocker,

@Silverrocker È anche POSIX (ad eccezione della bashparte ovviamente). La shell POSIX accetta un sacco di opzioni che sono applicabili a set. O vice versa? setè un modo per impostare le opzioni della riga di comando della shell all'interno dello script.
— Kaz

7
Sfortunatamente, ci sono un certo numero di utility standard che non seguono le solite convenzioni sullo stato di uscita, quindi -epossono comportarsi in modo errato. Ad esempio, probabilmente non vuoi che lo script venga chiuso ogni volta che diffdue file non identici. Puoi ovviamente ovviare a questo aggiungendo || true(o forse || [ $? = 1 ]) a tali comandi, ma l'OP menziona un "tutti gli altri" che dovranno leggere questo script e ha detto che "tutti gli altri" probabilmente non saranno abituati a dover far fronte -e.
— Ruakh

4
Avevo l'abitudine di fare il -ebotto, fino a quando un amministratore della mia compagnia continuava a lanciare i miei script bash myscript.sh, quindi ha ignorato il -e. Ora tutti i miei script hanno una set -eseconda riga.
— Carlos Campderrós,

19

Se non ti piace l' set -eidea, forse puoi invertire la logica.

foocommand || exit 1
foocommand2 || exit 2
foocommand3 || exit 3

Più utilmente, sostituiscilo exitcon qualcosa per stampare un utile messaggio di errore, quindi esci. All'interno di una funzione, ovviamente, vuoi returninvece di exit.


11
Oppure foocommand || exitper uscire con lo foocommandstato di uscita se diverso da zero.
— Stéphane Chazelas,

Come funziona? È come in C - se l'argomento sinistro restituisce VERO, non vengono controllati più argomenti?
— Vorac,

Sì, è giusto. È un linguaggio comune in Lisp (e nei linguaggi funzionali in generale, suppongo) e in Perl.
— Tripleee

9

Puoi if else fiinvece usare i blocchi.

if foocommand; then

  # some comments

  if foocommand2; then

    # more comments

    foocommand3
  fi
fi

È un po 'più leggibile.

In alternativa puoi semplicemente usare \per spezzare il tuo grande 1 liner in più righe

foocommand && \
  # some comment
  foocommand2 && \
    # more comment
    foocommand3

Ma ovviamente questo può confondere l'occhio non allenato.


4
Non credo \sia necessario lì.
— Samuel Edwin Ward,

Hai ragione. Forza dell'abitudine.
— Martín Canaval,

5

Puoi prendere in considerazione l'utilizzo di ifistruzioni nidificate . Un'altra opzione è quella di usare i ricci per raggruppare come{ true && echo hi; } || echo huh

Aggiornamento 1:

Ecco un esempio senza newline / commenti:

{ { false && echo "inner true"; } && { echo "inner true" && true; } || { echo "inner false" && false; } || echo "outter false"; }

@Stephane Grazie per aver aggiunto il punto e virgola. Ho usato il mio telefono per rispondere, quindi non ho ricontrollato le mie risposte. :)
— livingstaccato il

Idea interessante. Sì, avevo pensato alle dichiarazioni nidificate se ma se sto concatenando un sacco di cose insieme potrebbe diventare confuso.
— Mike B,

4

Dividi ogni sequenza di comandi in funzioni:

big_block_1() {
  # ...
}
big_block_2() {
  # ...
}
big_block_3() {
  # ...
}

big_block_1 && big_block_2 && big_block_3

0

Mi piace sempre scrivere una funzione "fail" che mi permetta di specificare la cosa che stavo per fare quando si è verificato l'errore e quindi utilizzare il ||modello. Come il seguente:

function fail() {
  echo "Failure: ${@}"
  exit 1
}

foocommand || fail "couldn't foo"
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.