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.