Odróżnianie zwykłego pliku od dowiązania symbolicznego


22

Piszę skrypt bash, który musi odróżniać zwykły plik od dowiązania symbolicznego. Myślałem, że mogę to zrobić za pomocą wyrażenia if / test, ale nie działa tak, jak się spodziewałem:

$ touch regular_file
$ test -f regular_file; echo $?
0
$ test -h regular_file; echo $?
1
$ ln -s regular_file symlink
$ test -h symlink; echo $?
0
$ test -f symlink; echo $?
0

Dlaczego? I jak mogę to właściwie zrobić?

Odpowiedzi:


20

Wygląda na to, że po prostu troszkę mieszasz swoje testy. Nie musisz uruchamiać obu testów, jedyne, czego potrzebujesz w tym przypadku, to to, -haby powiedzieć, czy plik jest dowiązaniem symbolicznym.

test -h file && echo "is symlink" || echo "is regular file"

-fTestu tylko mówi, jeśli obiekt jest plikiem. Zwróciłoby to, 0gdyby był katalogiem, węzłem urządzenia lub dowiązaniem symbolicznym do katalogu, ale 1zwróciłoby dowiązanie symboliczne do pliku.

Jeśli musisz wiedzieć, czy jest to dowiązanie symboliczne do pliku, a nie do katalogu, musisz połączyć wyniki obu testów z odrobiną logiki.


Jak zrozumiałem z dokumentacji, różnica między -ei -fbyła -eużywana -fdo sprawdzenia, czy plik (dowolnego typu) istnieje, a konkretnie do sprawdzenia, czy plik istnieje i czy jest zwykłym plikiem. Wygląda na to, że źle zrozumiałem, czym był „zwykły plik”.
Nupraptor,

1
@Nupraptor: Tak, źle zrozumiałeś dokumenty. Dowiązanie symboliczne jest uważane za zwykły plik, w przeciwieństwie do niektórych innych typów węzłów, którymi może być plik (węzeł blokowy, węzeł znakowy, katalog itp.). Jeśli chcesz wiedzieć, jaki to typ pliku, musisz przeprowadzić test specyficzny dla typu pliku, np. -hDla dowiązań symbolicznych, -pnazwanych potoków itp.
Caleb

Jak zatem sprawdzić, czy plik jest zwykłym plikiem w tym sensie, że nie jest potokiem ani dowiązaniem symbolicznym itp.? Czy powinienem otworzyć na to kolejne pytanie?
Nupraptor

@Nupraptor: Jedynym dziwnym przypadkiem jest dowiązanie symboliczne, które prowadzi do zwykłego pliku. W przeciwnym razie, jeśli testuje się jako zwykły plik, jest to zwykły plik.
David Schwartz

3
katalog test -f zwróci 1, a nie 0: test -f. ; echo $? (wyjścia 1)
wielomian

7

@Caleb ma rację, jeśli skrypt ma po prostu przetestować dowiązanie symboliczne. Jednak część o tym, dlaczego została pominięta, byłam ciekawa. Jeśli spojrzysz na kod źródłowy coreutils i przejrzysz wynik testu, zobaczysz, że po uruchomieniu testu dowiązania symbolicznego używa on lstat, a jeśli używasz testu -f, to tak naprawdę wywołuje „stat”, który następuje po dowiązaniu symbolicznym:

$ ln -s varnish_config XXX
$ strace -s 2000 test -L XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-L", "XXX"], [/* 47 vars */]) = 0
lstat("XXX", {st_mode=S_IFLNK|0777, st_size=14, ...}) = 0

$ strace -s 2000 test -L varnish_config 2>&1 | grep varnish
execve("/usr/bin/test", ["test", "-L", "varnish_config"], [/* 47 vars */]) = 0
lstat("varnish_config", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

$ strace -s 2000 test -f XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-f", "XXX"], [/* 47 vars */]) = 0
stat("XXX", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

Ze strony man statystyki:

   stat() stats the file pointed to by path and fills in buf.

   lstat() is identical to stat(), except that if path is a symbolic link,
   then the link itself is stat-ed, not the file that it refers to.

Oznacza to, że test -f zwróci wartość true, o ile podana nazwa pliku jest dowiązaniem symbolicznym do zwykłego pliku lub samego zwykłego pliku.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.