Trong
[ -f "$file" ]
các [
lệnh làm một stat()
(không lstat()
) gọi hệ thống trên con đường lưu trữ trong $file
và trả về đúng nếu đó là cuộc gọi hệ thống thành công và loại nội dung tập tin được trả về bởi stat()
là " bình thường ".
Vì vậy, nếu [ -f "$file" ]
trả về true, bạn có thể cho biết tệp tồn tại và là tệp thông thường hoặc liên kết tượng trưng cuối cùng sẽ phân giải thành tệp thông thường (hoặc ít nhất là tại thời điểm đó stat()
).
Tuy nhiên, nếu nó trả về false (hoặc nếu [ ! -f "$file" ]
hoặc ! [ -f "$file" ]
trả về true), có nhiều khả năng khác nhau:
- tập tin không tồn tại
- tệp tồn tại nhưng không phải là tệp thông thường (có thể là thiết bị, fifo, thư mục, ổ cắm ...)
- tập tin tồn tại nhưng bạn không có quyền tìm kiếm vào thư mục mẹ
- tệp tồn tại nhưng đường dẫn để truy cập nó quá dài
- tệp là một liên kết tượng trưng đến một tệp thông thường, nhưng bạn không có quyền tìm kiếm đối với một số thư mục liên quan đến độ phân giải của liên kết tượng trưng.
- ... Bất kỳ lý do nào khác khiến
stat()
cuộc gọi hệ thống có thể thất bại.
Nói tóm lại, nó nên là:
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
Để biết chắc chắn rằng tệp không tồn tại, chúng tôi cần stat()
gọi lại hệ thống với mã lỗi ENOENT
( ENOTDIR
cho chúng tôi biết một trong các thành phần đường dẫn không phải là thư mục là một trường hợp khác mà chúng tôi có thể nói với tệp không tồn tại theo con đường đó). Thật không may, [
lệnh không cho chúng tôi biết điều đó. Nó sẽ trả về false cho dù mã lỗi là ENOENT, EACCESS (quyền bị từ chối), ENAMETOOLONG hoặc bất cứ điều gì khác.
Các [ -e "$file" ]
thử nghiệm cũng có thể được thực hiện với ls -Ld -- "$file" > /dev/null
. Trong trường hợp đó, ls
sẽ cho bạn biết lý do stat()
thất bại, mặc dù thông tin không thể dễ dàng được sử dụng theo chương trình:
$ 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
Ít nhất ls
cho tôi biết không phải vì tập tin không tồn tại mà nó bị lỗi. Đó là bởi vì nó không thể biết liệu tập tin có tồn tại hay không. Các [
lệnh chỉ phớt lờ vấn đề.
Với zsh
shell, bạn có thể truy vấn mã lỗi với $ERRNO
biến đặc biệt sau [
lệnh fail và giải mã số đó bằng $errnos
mảng đặc biệt trong zsh/system
mô-đun:
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
(hãy cẩn thận với sự $errnos
hỗ trợ đã bị hỏng với một số phiên bản zsh
khi được xây dựng với các phiên bản gần đâygcc
).