W
[ -f "$file" ]
[
komenda robi stat()
(nie lstat()
) wywołanie systemowe na ścieżce przechowywanej w $file
i zwraca prawda jeśli się powiedzie, że wywołanie systemowe i typ pliku jako zwrócony przez stat()
to „ regular ”.
Więc jeśli [ -f "$file" ]
zwróci true, możesz powiedzieć, że plik istnieje i jest zwykłym plikiem lub dowiązaniem symbolicznym, które ostatecznie przekształca się w zwykły plik (lub przynajmniej tak było w momencie stat()
).
Jeśli jednak zwraca false (lub jeśli [ ! -f "$file" ]
lub ! [ -f "$file" ]
zwraca true), istnieje wiele różnych możliwości:
- plik nie istnieje
- plik istnieje, ale nie jest zwykłym plikiem (może to być urządzenie, fifo, katalog, gniazdo ...)
- plik istnieje, ale nie masz uprawnień do wyszukiwania w katalogu nadrzędnym
- plik istnieje, ale ścieżka dostępu do niego jest za długa
- plik jest dowiązaniem symbolicznym do zwykłego pliku, ale nie masz uprawnień do wyszukiwania do niektórych katalogów zaangażowanych w rozwiązywanie dowiązania symbolicznego.
- ... z jakiegokolwiek innego powodu, dla którego
stat()
wywołanie systemowe może zakończyć się niepowodzeniem.
Krótko mówiąc, powinno to być:
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
Aby mieć pewność, że plik nie istnieje, potrzebujemy stat()
wywołania systemowego z kodem błędu ENOENT
( ENOTDIR
mówi nam, że jeden ze składników ścieżki nie jest katalogiem, to kolejny przypadek, w którym możemy stwierdzić, że plik nie istnieje istnieje przy tej ścieżce). Niestety [
polecenie to nas nie informuje. Zwróci false, czy kod błędu to ENOENT, EACCESS (odmowa zgody), ENAMETOOLONG lub cokolwiek innego.
[ -e "$file" ]
Test może być również wykonane z ls -Ld -- "$file" > /dev/null
. W takim przypadku ls
powie Ci, dlaczego stat()
nie powiodło się, chociaż informacji nie można łatwo wykorzystać programowo:
$ 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
Przynajmniej ls
mówi mi, że to nie dlatego, że plik nie istnieje, że zawodzi. Jest tak, ponieważ nie można stwierdzić, czy plik istnieje, czy nie. [
Komenda prostu zignorował problem.
Za pomocą zsh
powłoki można wyszukać kod błędu za pomocą $ERRNO
specjalnej zmiennej po nieudanym [
poleceniu i zdekodować tę liczbę za pomocą $errnos
specjalnej tablicy w zsh/system
module:
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
(uwaga: $errnos
obsługa została zerwana z niektórymi wersjami zsh
po zbudowaniu z najnowszymi wersjamigcc
).