OS X, bash: менше працює на дескрипторах відкритих файлів, cat не працює


10

У bash-скрипті, над яким я працюю (який повинен працювати на Ubuntu та OS X), мені потрібно перенаправити висновок сотень команд у файл.
Замість того, щоб додати їх &>...до всіх, я просто роблю

exec 9>&1
exec 5<>/tmp/some-file.txt
exec 1>&5

Поки добре, але на півдорозі всіх цих команд мені потрібно прочитати все, що було написано дотепер, зберігаючи дескриптор файлів відкритим.
Тепер на Ubuntu я можу просто зробити

cat /dev/fd/5

або

tee </dev/fd/5

але на OS X нічого не друкується взагалі (і команди негайно виходять).
Однак за допомогою lessя можу побачити вміст файлу на обох.
Я можу досягти вищезазначеного ефекту (працюючи на обох ОС), використовуючи

less /dev/fd/5 | tee

але це здається злом.

Отже, чому, lessочевидно, можна бачити речі, які catне вдається в OS X? (Або всі нащадки BSD постраждали?)
Або я роблю щось не так?

Відповіді:


13

У 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.