Come faccio a sapere se un file regolare non esiste in Bash?

Ho usato il seguente script per vedere se esiste un file:

#!/bin/bash FILE=$1 if [ -f $FILE ]; then echo "File $FILE exists." else echo "File $FILE does not exist." fi 

Qual è la syntax corretta da usare se voglio solo verificare se il file non esiste?

 #!/bin/bash FILE=$1 if [ $FILE does not exist ]; then echo "File $FILE does not exist." fi 

Il comando test ( [ here) ha un operatore “not” logico che è il punto esclamativo (simile a molti altri linguaggi). Prova questo:

 if [ ! -f /tmp/foo.txt ]; then echo "File not found!" fi 

Bash File Testing

-b filename – Blocca file speciale
-c filename – File di caratteri speciali
-d directoryname : verifica la presenza di directory
-e filename – Verifica la presenza del file, indipendentemente dal tipo (nodo, directory, socket, ecc.)
-f filename – Verifica la presenza regolare di file non una directory
-G filename : controlla se il file esiste ed è di proprietà dell’ID di gruppo effettivo
-G filename set-group-id – Vero se il file esiste ed è set-group-id
-k filename – Bit appiccicoso
-L filename : collegamento simbolico
-O filename – Vero se il file esiste ed è di proprietà dell’id utente effettivo
-r filename – Controlla se il file è leggibile
-S filename – Controlla se il file è socket
-s filename – Controlla se il file è di dimensioni diverse da zero
-u filename – Controlla se il bit set-user-id è impostato
-w filename – Controlla se il file è scrivibile
-x filename – Controlla se il file è eseguibile

Come usare:

 #!/bin/bash file=./file if [ -e "$file" ]; then echo "File exists" else echo "File does not exist" fi 

Un’espressione test può essere negata usando il ! operatore

 #!/bin/bash file=./file if [ ! -e "$file" ]; then echo "File does not exist" else echo "File exists" fi 

Puoi negare un’espressione con “!”:

 #!/bin/bash FILE=$1 if [ ! -f "$FILE" ] then echo "File $FILE does not exist" fi 

La pagina man relativa è man test o, equivalentemente, man [ – o help test o help [ per il comando bash incorporato.

 [[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE" 

Inoltre, è ansible che il file sia un collegamento simbolico non funzionante o un file non regolare, ad esempio un socket, un dispositivo o un fifo. Ad esempio, per aggiungere un controllo per i collegamenti simbolici non funzionanti:

 if [[ ! -f $FILE ]]; then if [[ -L $FILE ]]; then printf '%s is a broken symlink!\n' "$FILE" else printf '%s does not exist!\n' "$FILE" fi fi 

Vale la pena ricordare che se è necessario eseguire un singolo comando, è ansible abbreviare

 if [ ! -f "$file" ]; then echo "$file" fi 

a

 test -f "$file" || echo "$file" 

o

 [ -f "$file" ] || echo "$file" 

Preferisco fare il seguente one-liner, in formato compatibile con shell POSIX :

 $ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND" $ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND" 

Per un paio di comandi, come farei in uno script:

 $ [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;} 

Una volta che ho iniziato a farlo, raramente uso più la syntax completamente digitata !!

Per verificare l’esistenza del file, il parametro può essere uno dei seguenti:

 -e: Returns true if file exists (regular file, directory, or symlink) -f: Returns true if file exists and is a regular file -d: Returns true if file exists and is a directory -h: Returns true if file exists and is a symlink 

Tutti i test seguenti si applicano a file, directory e collegamenti simbolici regolari:

 -r: Returns true if file exists and is readable -w: Returns true if file exists and is writable -x: Returns true if file exists and is executable -s: Returns true if file exists and has a size > 0 

Script di esempio:

 #!/bin/bash FILE=$1 if [ -f "$FILE" ]; then echo "File $FILE exists" else echo "File $FILE does not exist" fi 

Devi fare attenzione a eseguire il test per una variabile non quotata, perché potrebbe produrre risultati imprevisti:

 $ [ -f ] $ echo $? 0 $ [ -f "" ] $ echo $? 1 

La raccomandazione è di solito di avere la variabile testata circondata da doppie virgolette:

 #!/bin/sh FILE=$1 if [ ! -f "$FILE" ] then echo "File $FILE does not exist." fi 

Ci sono tre modi distinti per farlo:

  1. Annulla lo stato di uscita con bash (nessuna altra risposta ha detto questo):

     if ! [ -e "$file" ]; then echo "file does not exist" fi 

    O:

     ! [ -e "$file" ] && echo "file does not exist" 
  2. Annulla il test all’interno del comando di test [ (questo è il modo in cui la maggior parte delle risposte sono state presentate):

     if [ ! -e "$file" ]; then echo "file does not exist" fi 

    O:

     [ ! -e "$file" ] && echo "file does not exist" 
  3. Agisci sul risultato negativo del test ( || invece di && ):

    Solo:

     [ -e "$file" ] || echo "file does not exist" 

    Questo sembra stupido (IMO), non usarlo a meno che il tuo codice non debba essere trasferito alla shell Bourne (come /bin/sh di Solaris 10 o precedente) che mancava all’operatore di negazione della pipeline ( ! ):

     if [ -e "$file" ]; then : else echo "file does not exist" fi 

Puoi farlo:

 [[ ! -f "$FILE" ]] && echo "File doesn't exist" 

o

 if [[ ! -f "$FILE" ]]; then echo "File doesn't exist" fi 

Se vuoi controllare sia il file che la cartella, usa l’opzione -e invece di -f . -e restituisce true per file regolari, directory, socket, file speciali di caratteri, blocchi di file speciali, ecc.

In

 [ -f "$file" ] 

il comando [ esegue una chiamata di sistema stat() (non lstat() ) sul percorso archiviato in $file e restituisce true se tale chiamata di sistema ha lstat() positivo e il tipo di file restituito da stat() è “regolare”.

Quindi se [ -f "$file" ] restituisce true, puoi dire che il file esiste ed è un file normale o un link simbolico che alla fine si risolve in un file normale (o almeno era al momento della stat() ).

Tuttavia se restituisce false (o se [ ! -f "$file" ] o ! [ -f "$file" ] restituisce true), ci sono molte possibilità diverse:

  • il file non esiste
  • il file esiste ma non è un file normale
  • il file esiste ma non si dispone dell’authorization alla ricerca per la directory superiore
  • il file esiste ma quel percorso per accedervi è troppo lungo
  • il file è un collegamento simbolico a un file normale, ma non si dispone dell’authorization alla ricerca per alcune delle directory coinvolte nella risoluzione del collegamento simbolico.
  • … qualsiasi altra ragione per cui la chiamata di sistema stat() potrebbe fallire.

In breve, dovrebbe essere:

 if [ -f "$file" ]; then printf '"%s" is a path to a regular file or symlink to regular file\n' "$file" elif [ -e "$file" ]; then printf '"%s" exists but is not a regular file\n' "$file" elif [ -L "$file" ]; then printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file" else printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file" fi 

Per sapere con certezza che il file non esiste, avremmo bisogno che la chiamata di sistema stat() restituisca con un codice di errore ENOENT ( ENOTDIR ci dice che uno dei componenti del percorso non è una directory è un altro caso in cui possiamo dire il file non esiste per quel percorso). Sfortunatamente [ comando non ce lo fa sapere. Restituirà false se il codice di errore è ENOENT, EACCESS (permesso negato), ENAMETOOLONG o qualsiasi altra cosa.

Il test [ -e "$file" ] può essere eseguito anche con ls -Ld -- "$file" > /dev/null . In tal caso, ls ti spiegherà perché la stat() non è riuscita, sebbene le informazioni non possano essere facilmente utilizzate a livello di programmazione:

 $ file=/var/spool/cron/crontabs/root $ if [ ! -e "$file" ]; then echo does not exist; fi does not exist $ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi ls: cannot access '/var/spool/cron/crontabs/root': Permission denied stat failed 

Almeno ls mi dice che non è perché il file non esiste che fallisce. È perché non può sapere se il file esiste o meno. [ Il comando ha appena ignorato il problema.

Con la shell zsh , è ansible interrogare il codice di errore con la variabile speciale $ERRNO dopo il mancato [ comando e decodificare quel numero utilizzando l’array speciale $errnos nel modulo zsh/system :

 zmodload zsh/system ERRNO=0 if [ ! -f "$file" ]; then err=$ERRNO case $errnos[err] in ("") echo exists, not a regular file;; (ENOENT|ENOTDIR) if [ -L "$file" ]; then echo broken link else echo does not exist fi;; (*) echo "can't tell"; syserror "$err" esac fi 

(attenzione il supporto $errnos è rotto con alcune versioni di zsh se costruito con le versioni recenti di gcc ).

Per invertire un test, utilizzare “!”. Questo è equivalente all’operatore logico “non” in altre lingue. Prova questo:

 if [ ! -f /tmp/foo.txt ]; then echo "File not found!" fi 

O scritto in un modo leggermente diverso:

 if [ ! -f /tmp/foo.txt ] then echo "File not found!" fi 

O potresti usare:

 if ! [ -f /tmp/foo.txt ] then echo "File not found!" fi 

Oppure, presing tutti insieme:

 if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi 

Che può essere scritto (usando quindi “e” operatore: &&) come:

 [ ! -f /tmp/foo.txt ] && echo "File not found!" 

Che sembra più corto come questo:

 [ -f /tmp/foo.txt ] || echo "File not found!" 

Anche la test può contare. Ha funzionato per me (basato su Bash Shell: Check File Exists o Not ):

 test -e FILENAME && echo "File exists" || echo "File doesn't exist" 

Anche questo codice funziona.

 #!/bin/bash FILE=$1 if [ -f $FILE ]; then echo "File '$FILE' Exists" else echo "The File '$FILE' Does Not Exist" fi 

Il modo più semplice

 FILE=$1 [ ! -e "${FILE}" ] && echo "does not exist" || echo "exists" 

Questo script di shell funziona anche per trovare un file in una directory:

 echo "enter file" read -ra if [ -s /home/trainee02/"$a" ] then echo "yes. file is there." else echo "sorry. file is not there." fi 

a volte può essere utile usare && e || operatori.

Come in (se hai il comando “test”):

 test -b $FILE && echo File not there! 

o

 test -b $FILE || echo File there!