exec n <& m против exec n> & m - на основе книги Собелла о Linux - PullRequest
4 голосов
/ 04 мая 2011

В Практическом руководстве по командам, редакторам и программированию для Linux, второе издание Марка Собелла он пишет (стр. 432):

Знак <& дублируетдескриптор входного файла;> & дублирует дескриптор выходного файла.

Это кажется несовместимым с другим оператором на той же странице:

Используйте следующий формат для открытия или перенаправления дескриптора файла nв качестве дубликата дескриптора файла m:

exec n <& m </p>

и с примером на той же странице:

# File descriptor 3 duplicates standard input
# File descriptor 4 duplicates standard output
exec 3<&0 4<&1

If> & duplicatesдескриптор выходного файла, тогда мы не должны сказать

exec 4>&1

, чтобы дублировать стандартный вывод?

Ответы [ 3 ]

8 голосов
/ 04 мая 2011

Пример верен на практике.Оригинальное объяснение книги - точное описание того, что говорит стандарт POSIX, но POSIX-подобные оболочки, которые у меня есть (bash и dash, единственные, которые, как мне кажется, обычно встречаются в Linux), не настолько придирчивы.

Стандарт POSIX говорит то же самое, что и книга о дескрипторах ввода и вывода, и продолжает так: для n<&word, "если цифры в word не представляютдескриптор файла, уже открытый для ввода, приведет к ошибке перенаправления ".Поэтому, если вы хотите быть осторожнее с POSIX-совместимостью, вам следует избегать такого использования.

В документации bash также говорится то же самое о <& и >&, но без обещанияошибки.Что хорошо, потому что это не дает ошибки.Вместо этого эмпирически n<&m и n>&m кажутся взаимозаменяемыми.Единственная разница между <& и >& состоит в том, что если вы оставите номер fd слева, <& по умолчанию будет 0 (стандартный) и >& - 1 (стандартный).

ДляНапример, давайте запустим оболочку с fd 1, указывающей на файл bar, затем попробуем в точности пример exec 4<&1, попробуйте записать получившийся fd 4 и посмотреть, работает ли он:

$ sh -c 'exec 4<&1; echo foo >&4' >bar; cat bar
foo

Да, и это справедливо при использовании dash или bash (или bash --posix) для оболочки.

Под капотом это имеет смысл, потому что <& и> & почти наверняка просто вызывают dup2 () , которому все равно, открыты ли fds для чтения, записи или добавления или что.

[ EDIT : добавлена ​​ссылка на POSIX после обсужденияв комментариях.]

2 голосов
/ 04 мая 2011

Если стандартный вывод является tty, его можно безопасно клонировать для чтения или записи.Если stdout - это файл, он может не работать.Я думаю, что пример должен быть 4>&1.Я согласен с Грегом, что вы можете как читать, так и писать дескриптор клона, но запрос перенаправления с <& должен выполняться с исходными дескрипторами, которые доступны для чтения, и ожидать, что stdout будет читаемым, не имеет смысла.(Хотя я признаю, что у меня нет ссылки на это утверждение.)

Пример может прояснить ситуацию.С помощью этого сценария:

#!/bin/bash

exec 3<&0
exec 4<&1

read -p "Reading from fd 3: " <&3
echo From fd 3: $REPLY >&2
REPLY=
read -p "Reading from fd 4: " <&4
echo From fd 4: $REPLY >&2

echo To fd 3 >&3
echo To fd 4 >&4

я получаю следующий вывод (материал после строк: on "Reading from" набирается на терминале):

$ ./5878384b.sh
Reading from fd 3: foo
From fd 3: foo
Reading from fd 4: bar
From fd 4: bar
To fd 3
To fd 4
$ ./5878384b.sh < /dev/null
From fd 3:
Reading from fd 4: foo
From fd 4: foo
./5878384b.sh: line 12: echo: write error: Bad file descriptor
To fd 4
$ ./5878384b.sh > /dev/null
Reading from fd 3: foo
From fd 3: foo
./5878384b.sh: line 9: read: read error: 0: Bad file descriptor
From fd 4:
To fd 3
0 голосов
/ 04 мая 2011

Обратите внимание на разницу между файловыми дескрипторами и потоками ввода-вывода, такими как stderr и stdout.

Операторы перенаправления просто перенаправляют потоки ввода-вывода через разные файловые дескрипторы (механизмы обработки потока ввода-вывода);они не делают никакого копирования или дублирования потоков ввода-вывода (для этого предназначен tee (1)).

См .: Дескриптор файла 101

Еще один тест, чтобы показать, чтоn <& m и n> & m взаимозаменяемы: «использовать стиль 'n <& -» или «n> & -» для закрытия файлового дескриптора, даже если он не соответствует режиму чтения / записи, которыйдескриптор файла был открыт с помощью "(http://www.gnu.org/s/hello/manual/autoconf/File-Descriptors.html).

...