Come posso verificare se un comando genera una stringa vuota?
ifne
per questo. joeyh.name/code/moreutils
Come posso verificare se un comando genera una stringa vuota?
ifne
per questo. joeyh.name/code/moreutils
Risposte:
In precedenza, la domanda chiedeva come verificare se ci sono file in una directory. Il seguente codice lo raggiunge, ma vedi la risposta di rsp per una soluzione migliore.
I comandi non restituiscono valori, ma li generano. È possibile acquisire questo output utilizzando la sostituzione dei comandi ; es $(ls -A)
. Puoi testare una stringa non vuota in Bash in questo modo:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Nota che ho usato -A
piuttosto che -a
, dal momento che omette la corrente simbolica ( .
) e parent (..
voci directory ).
Nota: come sottolineato nei commenti, la sostituzione dei comandi non acquisisce nuove righe finali . Pertanto, se il comando genera solo nuove righe, la sostituzione non catturerà nulla e il test restituirà false. Anche se molto improbabile, questo è possibile nell'esempio sopra, poiché una singola riga è un nome file valido! Maggiori informazioni in questa risposta .
Se si desidera verificare che il comando sia stato completato correttamente, è possibile controllare $?
, che contiene il codice di uscita dell'ultimo comando (zero per esito positivo, diverso da zero per errore). Per esempio:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
Maggiori informazioni qui .
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Grazie a netj
per un suggerimento per migliorare il mio originale:if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Questa è una vecchia domanda ma vedo almeno due cose che richiedono qualche miglioramento o almeno qualche chiarimento.
Il primo problema che vedo è che la maggior parte degli esempi forniti qui semplicemente non funzionano . Usano i comandi ls -al
e ls -Al
- entrambi i quali producono stringhe non vuote in directory vuote. Questi esempi riportano sempre che ci sono file anche quando non ce ne sono .
Per questo motivo dovresti usare solo ls -A
- Perché qualcuno dovrebbe usare l' -l
opzione che significa "usa un formato di elenco lungo" quando tutto ciò che vuoi è testare se c'è qualche output o no, comunque?
Quindi la maggior parte delle risposte qui sono semplicemente errate.
Il secondo problema è che mentre alcune risposte funzionano bene (quelle che non lo fanno utilizzano ls -al
o ls -Al
ma ls -A
invece) tutti lo fanno qualcosa di simile:
Quello che suggerirei invece di fare sarebbe:
using head -c1
Ad esempio, invece di:
if [[ $(ls -A) ]]
Io userei:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
Invece di:
if [ -z "$(ls -lA)" ]
Io userei:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
e così via.
Per output piccoli potrebbe non essere un problema, ma per output più grandi la differenza può essere significativa:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
Confronta con:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
E ancora meglio:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
Esempio aggiornato dalla risposta di Will Vousden:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Aggiornato di nuovo dopo i suggerimenti di netj :
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Aggiornamento aggiuntivo di jakeonfire :
grep
uscirà con un errore se non c'è corrispondenza. Possiamo trarne vantaggio per semplificare leggermente la sintassi:
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
echo "no files found"
fi
Se il comando che stai testando potrebbe generare degli spazi bianchi che vuoi trattare come una stringa vuota, invece di:
| wc -c
potresti usare:
| tr -d ' \n\r\t ' | wc -c
o con head -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
o qualcosa di simile.
Innanzitutto, utilizza un comando che funzioni .
In secondo luogo, evitare l'archiviazione non necessaria nella RAM e l'elaborazione di dati potenzialmente enormi.
La risposta non ha specificato che l'output è sempre piccolo, quindi è necessario considerare anche una possibilità di output di grandi dimensioni.
[[ $(... | head -c | wc -c) -gt 0 ]]
o [[ -n $(... | head -c1) ]]
sono migliori perché wc -c
dovrebbero consumare l'intero output del comando.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Questo eseguirà il comando e verificherà se l'output restituito (stringa) ha lunghezza zero. Potresti voler controllare le pagine del manuale 'test' per altre bandiere.
Usa "" attorno all'argomento che viene controllato, altrimenti i risultati vuoti comporteranno un errore di sintassi poiché non c'è un secondo argomento (da controllare) dato!
Nota: che ls -la
ritorna sempre .
e ..
quindi l'utilizzo che non funzionerà, consultare le pagine di manuale . Inoltre, sebbene possa sembrare comodo e facile, suppongo che si rompa facilmente. Scrivere un piccolo script / applicazione che restituisce 0 o 1 a seconda del risultato è molto più affidabile!
$(
invece di backquote, perché $(
nidifica meglio
Per coloro che desiderano una soluzione elegante, indipendente dalla versione bash (in realtà dovrebbe funzionare in altre shell moderne) e coloro che amano usare una linea per compiti veloci. Eccoci qui!
ls | grep . && echo 'files found' || echo 'files not found'
(nota come uno dei commenti menzionati, ls -al
e in effetti solo -l
e -a
restituirà qualcosa, quindi nella mia risposta uso semplicels
grep -q ^
invece, verranno abbinati anche i caratteri di nuova riga e grep non stamperà nulla sull'output standard. Inoltre, uscirà non appena riceverà qualsiasi input, anziché attendere la fine del suo flusso di input.
ls -A
se vuoi includere dot-file (o directory)
Manuale di riferimento di Bash
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
Puoi usare la versione abbreviata:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
string
è solo sinonimo di -n string
.
Come ha commentato Jon Lin, ls -al
uscirà sempre (per .
e ..
). Tu vuoils -Al
evitare queste due directory.
Ad esempio, è possibile inserire l'output del comando in una variabile shell:
v=$(ls -Al)
Una notazione più vecchia, non annidabile, è
v=`ls -Al`
ma preferisco la notazione annidabile $(
...)
È possibile verificare se quella variabile non è vuota
if [ -n "$v" ]; then
echo there are files
else
echo no files
fi
E potresti combinare entrambi come if [ -n "$(ls -Al)" ]; then
Immagino che tu voglia l'output del ls -al
comando, quindi in bash avresti qualcosa del tipo:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
non viene mai eseguito. Verifica solo se l' espansione della variabile LS
non è vuota.
-a
interruttore non tornerà mai più alcun contenuto (cioè, tornerà contenuto se vi sono file o no) in quanto c'è sempre la implicita .
e ..
le directory presenti.
Ecco una soluzione per casi più estremi:
if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi
Questo funzionerà
però,
Tutte le risposte fornite finora hanno a che fare con comandi che terminano e generano una stringa non vuota.
La maggior parte sono rotti nei seguenti sensi:
yes
.).Quindi, per risolvere tutti questi problemi e rispondere in modo efficiente alla seguente domanda,
Come posso verificare se un comando genera una stringa vuota?
Puoi usare:
if read -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
È inoltre possibile aggiungere un timeout in modo da verificare se un comando genera una stringa non vuota entro un determinato tempo, usando read
l' -t
opzione di. Ad esempio, per un timeout di 2,5 secondi:
if read -t2.5 -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Osservazione. Se ritieni di dover determinare se un comando genera una stringa non vuota, molto probabilmente hai un problema XY.
seq 1 10000000
, seq 1 20
e printf""
). L'unico matchup che questo approccio di lettura non ha vinto è stato con l' -z "$(command)"
approccio per un input vuoto. Anche allora, perde solo circa il 10-15%. Sembrano andare in pareggio seq 1 10
. Indipendentemente da ciò, l' -z "$(command)"
approccio diventa così lento con l'aumentare delle dimensioni dell'input che eviterei di usarlo per qualsiasi input di dimensioni variabili.
Ecco un approccio alternativo che scrive lo std-out e lo std-err di alcuni comandi in un file temporaneo, quindi controlla se quel file è vuoto. Un vantaggio di questo approccio è che cattura entrambi gli output e non usa sub-shell o pipe. Questi ultimi aspetti sono importanti perché possono interferire con la gestione delle uscite di trapping bash (ad es. Qui )
tmpfile=$(mktemp)
some-command &> "$tmpfile"
if [[ $? != 0 ]]; then
echo "Command failed"
elif [[ -s "$tmpfile" ]]; then
echo "Command generated output"
else
echo "Command has no output"
fi
rm -f "$tmpfile"
A volte si desidera salvare l'output, se non è vuoto, per passarlo a un altro comando. Se è così, potresti usare qualcosa del genere
list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
/bin/rm $list
fi
In questo modo, il rm
comando non si bloccherà se l'elenco è vuoto.