In
[ -f "$file" ]
il [
comando esegue una stat()
(non lstat()
) chiamata di sistema sul percorso memorizzato $file
e restituisce true se la chiamata di sistema ha esito positivo e il tipo di file restituito dastat()
è " 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 lo era al momento delstat()
).
Tuttavia, se restituisce false (o if[ ! -f "$file" ]
o ! [ -f "$file" ]
return true), ci sono molte diverse possibilità:
- il file non esiste
- il file esiste ma non è un normale file (potrebbe essere un dispositivo, fifo, directory, socket ...)
- il file esiste ma non si dispone dell'autorizzazione di ricerca nella directory principale
- 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 di ricerca per alcune directory coinvolte nella risoluzione del collegamento simbolico.
- ... qualsiasi altro motivo per cui la
stat()
chiamata di sistema potrebbe non riuscire.
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 stat()
chiamata di sistema ritorni con un codice di errore di ENOENT
( ENOTDIR
ci dice che uno dei componenti del percorso non è una directory è un altro caso in cui possiamo dire che il file non esiste da quel percorso). Sfortunatamente il [
comando non ce lo fa sapere. Restituirà falso se il codice di errore è ENOENT, EACCESS (autorizzazione negata), ENAMETOOLONG o qualsiasi altra cosa.
Il [ -e "$file" ]
test può anche essere eseguito con ls -Ld -- "$file" > /dev/null
. In tal caso, ls
ti dirà perché l' stat()
errore non è riuscito, sebbene le informazioni non possano essere facilmente utilizzate a livello di codice:
$ 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 non riesce. È perché non può dire se il file esiste o no. Il [
comando ha semplicemente ignorato il problema.
Con la zsh
shell, è possibile eseguire una query sul codice di errore con la $ERRNO
variabile speciale dopo il [
comando non riuscito e decodificare quel numero utilizzando l' $errnos
array speciale nel zsh/system
modulo:
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;;
(*) syserror -p "can't tell: " "$err"
esac
fi
(attenzione il $errnos
supporto è stato interrotto con alcune versioni di zsh
quando costruito con versioni recenti digcc
).