У OS X, як і у всіх системах, де вони підтримуються, окрім Linux , відкриття /dev/fd/x
- це як робити dup(x)
, в результаті fd більш-менш вказує на той самий опис відкритого файлу, що і на fd x, і, зокрема, матиме однаковий зсув у файлі.
Тут є виключенням Linux. В Linux /dev/fd/x
є символьним посиланням на /proc/self/fd/x
і /proc/self/fd/x
є псевдосимвольним посиланням на файл, відкритий на fd x. У Linux, коли ви робите open("/dev/fd/x", somemode)
, ви отримуєте абсолютно новий відкритий опис файлу до того ж файлу, що і відкритий на 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()
на цьому fd початок файлу (чи 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