Come verificare se esiste un file in uno script di shell


176

Vorrei scrivere uno script di shell che controlla se archived_sensor_data.jsonesiste un determinato file e, in tal caso, lo elimina. A seguito di http://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditional-expressions.html , ho provato quanto segue:

[-e archived_sensor_data.json] && rm archived_sensor_data.json

Tuttavia, questo genera un errore

[-e: command not found

quando provo a eseguire lo test_controllerscript risultante usando il ./test_controllercomando. Cosa c'è di sbagliato nel codice?



2
Devi impostare uno o più spazi bianchi tra la parentesi quadra aperta "[" e l'opzione "-e" come tra nome file e parentesi quadra chiusa "]"
Konstantin Yaniv

Risposte:


351

Ti manca uno spazio richiesto tra la parentesi e -e:

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi

12
Ho finalmente aggiunto due spazi, uno dopo l'apertura parentesi quadra e uno prima quella di chiusura: [ -e archived_sensor_data.json ] && rm archived_sensor_data.json. La sceneggiatura sembra funzionare ora.
Kurt Peek,

3
Funziona anche usando if [ -e "$1" ](argomento input file).
Edward,

2
La differenza principale qui sta nel fatto che stai usando lo script "bash" invece dello script "shell". Nota che la prima riga che hai aggiunto era #! / Bin / bash, quindi stai dicendo alla macchina di usare "bash" invece di sh. Perché sh non riconosce quell'argomento "-e"
Nick Cuevas il

29

Ecco un metodo alternativo che utilizza ls:

(ls x.txt && echo yes) || echo no

Se si desidera nascondere qualsiasi output da lscosì si vede solo sì o no, redirect stdoute stderrper /dev/null:

(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no

1
Questo codice significa: "se ha lsesito positivo, esiste un file del genere, altrimenti non ce n'è". Se lsfallito, ciò non significa che il file sia mancante. Potrebbe esserci qualche altro errore. Ad esempio, crea il file nella directory di proprietà di root e prova a farlo lscon un utente normale. Fallirà Permission denied, il che non equivale a che il file non esiste.
Tigran,

9

Lo sfondo della mia raccomandazione di soluzione è la storia di un amico che, nella seconda settimana del suo primo lavoro, ha cancellato mezzo server di build. Quindi l'attività di base è capire se esiste un file e, in tal caso, eliminiamolo. Ma ci sono alcune rapide insidiose su questo fiume:

  • Tutto è un file.

  • Gli script hanno un vero potere solo se risolvono compiti generali

  • Per essere generali, usiamo le variabili

  • Usiamo spesso -f force negli script per evitare l'intervento manuale

  • E anche l'amore -r ricorsivo per essere sicuri di creare, copiare e distruggere in modo tempestivo.

Considera il seguente scenario:

Abbiamo il file che vogliamo eliminare: filesexists.json

Questo nome file è memorizzato in una variabile

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

Abbiamo anche una variabile path per rendere le cose davvero flessibili

<host>:~/Documents/thisfolderexists pathtofile=".."

<host>:~/Documents/thisfolderexists ls $pathtofile

filesexists.json  history20170728  SE-Data-API.pem  thisfolderexists

Quindi vediamo se -efa quello che dovrebbe. I file esistono?

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Lo fa. Magia.

Tuttavia, cosa accadrebbe se la variabile del file venisse accidentalmente valutata come nuffin '

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Che cosa? Dovrebbe tornare con un errore ... E questo è l'inizio della storia di come l'intera cartella è stata cancellata per caso

Un'alternativa potrebbe essere quella di testare in modo specifico ciò che riteniamo essere un "file"

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

0

Quindi il file esiste ...

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

1

Quindi questo non è un file e forse non vogliamo cancellare l'intera directory

man test ha il seguente da dire:

-b FILE

       FILE exists and is block special

-c FILE

       FILE exists and is character special

-d FILE

       FILE exists and is a directory

-e FILE

       FILE exists

-f FILE

       FILE exists and is a regular file

...

-h FILE

       FILE exists and is a symbolic link (same as -L)

4

Internamente, il comando rm deve comunque verificare l'esistenza del file,
quindi perché aggiungere un altro test? Rilascio

rm filename

e sarà andato dopo, che fosse lì o no.
Usa rm -f se non vuoi messaggi su file inesistenti.

Se è necessario eseguire alcune azioni se il file NON esiste, è necessario verificarlo da soli. In base al codice di esempio, in questo caso non è così.


1
Questa è in realtà una risposta abbastanza valida per il comando rm. Per altri comandi suggerisco piuttosto di provare con -e.
Warhansen,

Solo che non è quello che fa la domanda.
Crayons,

1
È molto quello che fa la domanda, se leggi l' intera domanda, inclusa la parte "... e (se sì) ... la cancella".
TG

1

Se stai usando un NFS, "test" è una soluzione migliore, perché puoi aggiungere un timeout ad esso, nel caso in cui il tuo NFS sia inattivo:

time timeout 3 test -f 
/nfs/my_nfs_is_currently_down
real    0m3.004s <<== timeout is taken into account
user    0m0.001s
sys     0m0.004s
echo $?
124   <= 124 means the timeout has been reached

Un costrutto "[-e my_file]" si bloccherà fino a quando NFS non sarà nuovamente funzionante:

if [ -e /nfs/my_nfs_is_currently_down ]; then echo "ok" else echo "ko" ; fi

<no answer from the system, my session is "frozen">

teste [sono sinonimi. Puoi usarlo anche timeoutcon [, e testsi blocca anche se NFS si blocca.
quell'altro ragazzo il
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.