In
[ -f "$file" ]
il [comando esegue una stat()(non lstat()) chiamata di sistema sul percorso memorizzato $filee 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( ENOTDIRci 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, lsti 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 lsmi 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 zshshell, è possibile eseguire una query sul codice di errore con la $ERRNOvariabile speciale dopo il [comando non riuscito e decodificare quel numero utilizzando l' $errnosarray speciale nel zsh/systemmodulo:
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 $errnossupporto è stato interrotto con alcune versioni di zshquando costruito con versioni recenti digcc ).