Как работает `cat <> file`?

42

cat < fileпечатает содержимое файла на стандартный вывод

cat > fileчитает стандартный ввод до тех пор, пока не будет обнаружен знак Ctrl+, Dа введенный текст записывается в файл .

cat <> fileпо крайней мере в моей версии Bash, печатает содержимое файла счастливо (без ошибок), но не изменяет файл и не обновляет метку времени изменения.

Как стандарт Bash оправдывает кажущееся игнорирование >в третьем утверждении - и, что более важно, он что- то делает ?

Qix
источник

Ответы:

47

Bash использует <>для создания дескриптора файла для чтения и записи :

Оператор перенаправления

[n]<>word

приводит к открытию файла, имя которого является расширением слова, для чтения и записи в файловом дескрипторе n или в файловом дескрипторе 0, если n не указано. Если файл не существует, он создается.

cat <> fileоткрывает fileчтение-запись и привязывает его к дескриптору 0 (стандартный ввод). По сути, это эквивалентно < fileлюбой разумно написанной программе, поскольку никто, скорее всего, не попытается записать в стандартный ввод, но если бы он это сделал, он смог бы.

Вы можете написать простую программу C , чтобы проверить , что непосредственно - write(0, "hello", 6)запишет helloв fileчерез стандартный ввод.

<>также должен работать в любой другой POSIX-совместимой оболочке с тем же эффектом.

Майкл Гомер
источник
1
Пишем ... в stdin? ... Есть ли для этого какой-либо действительный вариант использования?
Qix
3
Я не могу придумать ничего хорошего. Предоставление явного дескриптора ( 4<>file) полезно, и я полагаю, что значение 0 по умолчанию так же хорошо, как и любое, когда вы его опускаете. Чтение со стандартного выхода не лучше.
Майкл Гомер
5
<>В некоторых системах (например, в Linux) также полезно открывать именованные каналы без блокировки, пока другой процесс не откроет их для записи.
Стефан Шазелас
1
@Qix: Хорошо, напишите (0, «Password:», 10) - это хороший способ запросить пароль, если вы намереваетесь запросить что-либо вроде tty. Я привык видеть это только на stderr, но без причины, в частности, та же самая техника не работает на stdin.
Джошуа
3
@Qix - из Обоснования POSIX - <>Оператор может быть полезен при написании приложения, которое работает с несколькими терминалами, и иногда хочет запустить оболочку. Эта оболочка, в свою очередь, не сможет запускать приложения, которые запускаются с обычного управляющего терминала, если она не сможет использовать <>... такой как ... пейджер more, который читает из стандартной ошибки, чтобы получить свои команды, поэтому стандартный ввод и стандартный вывод оба доступны для их обычного использования. cat food | more - >/dev/tty03 2<>/dev/tty03
mikeserv
38

<> fileоткрывает файл (на файловый дескриптор 0 (стандартного ввода) по умолчанию, как <) в чтение + запись режиме без усечения и создания файла , если он не существует заранее .

Это соответствует O_RDWR|O_CREATфлагам, переданным open()системному вызову. В отличие от этого <есть O_RDONLYи >есть O_WRONLY|O_CREAT|O_TRUNCи >> O_WRONLY|O_CREAT|O_APPEND.

Возможность записи в stdin не часто полезна, поскольку приложения обычно не пишут в их stdin. Приложения обычно не ожидают чтения и записи в файловом дескрипторе, который они получают при запуске; они обычно читают из stdin (или файлового дескриптора, который они открывают сами) и записывают в stdout или stderr (или файловый дескриптор, который они открывают сами).

<> может иметь свое использование:

  • Вы можете предпочесть cat <> fileболее, cat < fileесли вы не хотите, чтобы команда потерпела неудачу, если fileона не существует, а fileвместо этого создана пустая .
  • Не усеченный аспект <>делает полезным перезаписывать файлы на месте. Однако в этом случае вы обычно не используете его в дескрипторе файла 0:

    printf xxx 1<> file

    заменяет первые 3 байта fileс xxx.

  • В некоторых системах, таких как Linux, <>в именованном канале (FIFO) открывает именованный канал без блокировки (не дожидаясь, пока какой-либо другой процесс откроет другой конец), и обеспечивает сохранение структуры канала. Например, в:

    mkfifo pipe; sed 's/foo/bar/g' <> pipe

    sedобрабатывает входящие данные из любого числа других процессов, записывающих в него, и никогда не видит eof.

Стефан Шазелас
источник
1
Обратите внимание, что в AT & T ksh93 по <>умолчанию используется 1<>(stdout) вместо 0<>(stdin). Это ошибка соответствия POSIX, о которой я сообщил, и она будет исправлена ​​в следующем выпуске. github.com/att/ast/issues/75 Но до тех пор, пока текущие версии ksh93 не выйдут из употребления, вы должны включить номер дескриптора файла, чтобы использовать его <>переносимо.
Мартин Деккер
@MartijnDekker, я знаю, я был первым, кто рассказывал тебе об этом ;-). Обратите внимание, что это только для ksh93t + (где изменилось поведение) и выше.
Стефан Шазелас
Какие (или были) системы, в отличие от Linux, где mkfifo fifo; exec 3<>fifoблокировать?
Дядя Билли