Як працює `cat <> file`?


42

cat < fileдрукує вміст файлу до stdout.

cat > fileчитає stdin, поки не буде виявлено Ctrl+ D, і введений текст записується у файл .

cat <> file, принаймні в моїй версії Bash, друкує вміст файлу щасливо (без помилок), але не змінює файл і не оновлює часову позначку модифікації.

Як стандарт Баша виправдовує, здавалося б, ігноровану >в третьому твердженні - і, що ще важливіше, чи робить це щось?

Відповіді:


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 є настільки ж хорошим за замовчуванням, як і будь-який, коли ви його не залишаєте. Читання з stdout не є кращим.
Майкл Гомер

5
<>також корисно в деяких системах (наприклад, Linux) відкривати названі труби без блокування, поки інший процес не відкриє його для запису.
Стефан Шазелас

1
@Qix: Добре пишіть (0, "Пароль:", 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/isissue/75 Але поки поточні версії ksh93 не вийдуть з використання, вам потрібно включити номер дескриптора файлу, щоб використовувати його <>портативно.
Martijn Dekker

@MartijnDekker, я знаю, я саме про це розповів, в першу чергу ;-). Зауважте, що це стосується лише ksh93t + (де змінилася поведінка) та вище.
Стефан Шазелас

Які (або були) системи, на відміну від Linux, де mkfifo fifo; exec 3<>fifoб заблокували?
Дядько Біллі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.