2013-06-28 2 views
6

Come verificare in modo efficiente se un comando arbitrario ha prodotto un output nella shell POSIX? (Diciamo git ls-files --killed.)Come verificare se un output del comando non è vuoto nella shell POSIX?

Ci sono tre modi ovvi, ma ognuno sembra brutto o il male a me:

  1. [-n ​​"$ (git LS-files --killed)"] - l'output completo del comando deve essere catturato nella memoria e passato a prova (che è almeno si spera, un built-in)
  2. [ "$ (git ls-files --killed | wc -c)" -gt 0] - due fork-exec coinvolti
  3. TMP = $ (tempfile); git ls-files --killed> "$ tempfile"; [-s "$ tempfile"] & & ...; rm "$ tempfile" - è richiesto un file temporaneo intermedio (anche in questo caso catturare tutto l'output)

risposta

4

È anche possibile controllare lo stato di uscita del comando. Di solito, i comandi se con successo eseguito, restituire un exit status di 0.

git ls-files --killed > /dev/null 
if [ $? -eq 0 ] 

O se si vuole dipendere solo l'output del comando, è possibile utilizzare la "head -1" insieme con voi prima opzione in quanto comunque è sembra che tu non stia facendo alcuna elaborazione con il tuo output di comando oltre a conoscere il risultato.

+1

git ls-files - restituzioni restituite riuscite indipendentemente dal numero di file trovati come ls. – matthewbauer

+0

Grazie! Ovviamente, 'head -n 1' è esattamente ciò che mi mancava, perfetto. (Nota che non considero la tua prima risposta tanto rilevante quanto il ritorno/non ritorno dell'output è qualcosa di molto diverso dal successo/fallimento. Inoltre, considererei più elegante usare una versione più succinta 'se git ls- file --killed>/dev/null; then ...; fi'. –

+0

(... anche se coinvolge anche due fork. Penso comunque che sia la migliore alternativa finora suggerita.) –

1

Si potrebbe pensare che questa soluzione sia altrettanto hacky degli altri, ma penso che utilizzi meno memoria rispetto agli altri (non sono esperto di efficienza degli script di shell).

il codice è solo bash:

z=0 
while read -r -n1 char; do 
    z=1 
    break 
done < <(git ls-files --killed) 
[ $z != 0 ] 

Esso utilizza una variabile temporanea invece di un file temporaneo, e credo che leggere le opere solo un carattere alla volta, ma l'LS-file git comando può ancora eseguire completamente.

Potrebbe non essere molto meno brutto, ma penso che potrebbe essere almeno più efficiente.

+1

Grazie, è un bella idea, l'unico grande svantaggio è che è fortemente bash specifico: –

-1

Poiché si parla di POSIX, farò riferimento a questo answer
Io userei/usr/bin/test perché è richiesto sui sistemi POSIX.

/usr/bin/test -n "$(git ls-files --killed)"

+0

Mi dispiace, non capisco come sia rilevante. POSIX dovrebbe garantire un semplice test/[comportarsi in modo appropriato, e la soluzione è quindi lo stesso di uno dei miei. –

+0

D'accordo, credo che la tua prima soluzione sia la migliore o la più efficiente, poiché non si creano forche (molto probabilmente) e non si richiede l'output. – dougEfresh

3

mia soluzione preferita utilizza shell POSIX builtin read

if git ls-files --killed | read REPLY; then 
    echo "Some output" 
else 
    echo "No output or git failed" 
fi 

read tentativi di leggere una linea da stdin (e nella variabile REPLY), e restituisce 0 in caso di successo, o positivo codice di uscita se fallito. Il resto della pipeline non viene letto. Solo in bash, REPLY è il nome predefinito se omesso, pertanto read REPLY può essere ridotto a solo read.

Un potenziale svantaggio di questo approccio è che il codice di uscita del programma in questione (git nel tuo esempio) non è controllato.