В OS X, как и во всех системах, где они поддерживаются, кроме Linux , открытие /dev/fd/xпохоже на выполнение a dup(x), результирующий fd более или менее указывает на то же описание открытого файла, что и на fd x, и, в частности, будет иметь такое же смещение внутри файла.
Linux здесь исключение. В Linux /dev/fd/xэто символическая ссылка /proc/self/fd/xи /proc/self/fd/xпсевдосимвольная ссылка на файл, открытый на fd x. В Linux, когда вы делаете a open("/dev/fd/x", somemode), вы получаете совершенно новое описание открытого файла в том же файле, что и open x. Новый полученный вами fd никак не связан с fd x. В частности, смещение будет в начале файла (кроме случаев, когда вы, O_APPENDконечно, открываете его ), а режим (чтение / запись / добавление ...) может отличаться от режима на fd x (вы даже можете получить нечто совершенно отличное от того, что есть на fd x, например, другой конец трубы при открытии в противоположном режиме). (Это также означает, что это не работает для сокетов, например, которые вы не можете открыть () ).
Итак, в Linux, когда вы делаете
exec 5<> file
echo test >&5
Смещение fd 5 находится в конце файла. Если вы делаете
cat <&5
Вы ничего не получите.
Тем не менее, когда вы делаете:
cat /dev/fd/5
Вы видите, testпотому что catполучает новый доступный только для чтения fd, fileне связанный с fd 5.
В других системах, после
cat /dev/fd/5
cat получает fd, который является дубликатом fd 5, поэтому все еще со смещением в конце файла.
Причина, по которой он работает, lessзаключается в том, что по какой-то причине lessвыполняет lseek()поиск в этом файле до начала файла (делает, lseek(1); lseek(0)чтобы определить, является ли файл доступным для поиска или нет).
Здесь вы, вероятно, хотите иметь fd для чтения и один для записи, если вы хотите, чтобы оба имели разные смещения:
exec 5< file 9>&1 > file
Или вам придется заново открыть файл, если он все еще там, или сделать lseek()как less.
ksh93и zshявляются единственными оболочками со встроенным lseek()оператором:
cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin
Или:
cat /dev/fd/5 5<#((0)) # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh