W OS X, podobnie jak we wszystkich systemach, w których są obsługiwane oprócz Linuksa , otwieranie /dev/fd/x
jest jak robienie dup(x)
, wynikowy fd mniej więcej wskazuje ten sam opis otwartego pliku jak na fd x, a w szczególności będzie miał takie samo przesunięcie w pliku.
Linux jest tutaj wyjątkiem. W systemie Linux /dev/fd/x
jest dowiązaniem do /proc/self/fd/x
i /proc/self/fd/x
jest pseudo-dowiązaniem do otwartego pliku na fd x. W systemie Linux, gdy to zrobisz open("/dev/fd/x", somemode)
, otrzymasz zupełnie nowy opis otwartego pliku do tego samego pliku, co otwarty x
. Otrzymany nowy fd nie jest w żaden sposób powiązany z fd x. W szczególności przesunięcie będzie na początku pliku (chyba że otworzysz go O_APPEND
oczywiście), a tryb (odczyt / zapis / dołącz ...) może różnić się od tego na fd x (możesz nawet uzyskać coś zupełnie innego niż na fd x, jak drugi koniec potoku podczas otwierania go w trybie przeciwnym). (Oznacza to również, że nie działa to na przykład dla gniazd, których nie można otworzyć () ).
Więc w Linuksie, kiedy to robisz
exec 5<> file
echo test >&5
Przesunięcie fd 5 znajduje się na końcu pliku. Jeśli zrobisz
cat <&5
Nic nie dostaniesz
Nadal kiedy to robisz:
cat /dev/fd/5
Widzisz, test
ponieważ cat
dostaje nowy fd tylko do odczytu, file
niezwiązany z fd 5.
W innych systemach
cat /dev/fd/5
cat
dostaje fd, który jest duplikatem fd 5, więc nadal z przesunięciem na końcu pliku.
Powodem, dla którego działa, less
jest to, że z jakiegoś powodu less
robi to lseek()
na początku pliku ( lseek(1); lseek(0)
sprawdza, czy plik jest widoczny).
Tutaj prawdopodobnie chcesz mieć fd do czytania i jeden do pisania, jeśli chcesz, aby oba miały różne przesunięcia:
exec 5< file 9>&1 > file
Lub będziesz musiał ponownie otworzyć plik, jeśli nadal istnieje, lub zrobić lseek()
jak less
robi.
ksh93
i zsh
są jedynymi powłokami z wbudowanym lseek()
operatorem:
cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin
Lub:
cat /dev/fd/5 5<#((0)) # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh