operatori - script bash log




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

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"

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 sintassi 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

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

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

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

Nel

[ -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'autorizzazione 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'autorizzazione 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 , è possibile 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!"

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 sintassi completamente digitata !!


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.


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

echo "enter file"

read -r a

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

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

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

a

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

o

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

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 

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

Inoltre, è possibile 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




scripting