OS X, bash: меньше работает над дескрипторами открытых файлов, кошка не

В сценарии 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?)
Или я делаю что-то неправильно?

10 голосов | спросил Siguza 14 J0000006Europe/Moscow 2015, 21:34:11

1 ответ


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, конечно) и режима (прочитайте /write /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
ответил Stéphane Chazelas 15 J0000006Europe/Moscow 2015, 00:47:20

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132