Чому я не можу прочитати / dev / stdout з текстовим редактором?


9

Я тільки почав дізнаватися, як Everything Is A File TM на Linux, що змусило мене замислитися, що буде, якщо я буквально читаю з / dev / stdout:

$ cat /dev/stdout 
^C
$ tail /dev/stdout 
^C

( ^CМене вбиває програма після того, як вона висить).

Коли я намагаюся vim, я отримую немислиме повідомлення: "/ dev / stdout" не є файлом. Гасп!

Отже, що дає, чому я отримую повісити чи повідомлення про помилки, коли намагаюся прочитати ці "файли"?


1
Те, що vim вважає файлом і що означає "все - це файл" (без асоційованої торговельної марки) в * nix, не те саме. Див., Наприклад, №1 та №2 .
золотинок

Відповіді:


11

чому я отримую зависання

Ви не отримуєте "зависання" з, cat(1)і tail(1)вони просто блокують прочитане. cat(1)чекає на введення та друкує його, як тільки побачить повний рядок:

$ cat /dev/stdout
foo
foo
bar
bar

Тут я набрав fooEnterbarEnterCTRL- D.

tail(1)чекає на введення та друкує його лише тоді, коли він може виявити EOF:

$ tail /dev/stdout
foo
bar
foo
bar

Тут я знову набрав fooEnterbarEnterCTRL- D.

або повідомлення про помилки

Vim - єдиний, хто дає помилку. Це робиться тому, що він працює stat(2) проти /dev/stdout, і він вважає, що у нього не встановлено S_IFREGбіт.

/dev/stdoutце файл, але не звичайний файл. Насправді в ядрі є деякий танець, щоб дати йому запис у файловій системі. У Linux:

$ ls -l /dev/stdout
lrwxrwxrwx 1 root root 15 May  8 19:42 /dev/stdout -> /proc/self/fd/1

На OpenBSD:

$ ls -l /dev/stdout
crw-rw-rw-  1 root  wheel   22,   1 May  7 09:05:03 2015 /dev/stdout

На FreeBSD:

$ ls -l /dev/stdout
lrwxr-xr-x  1 root  wheel  4 May  8 21:35 /dev/stdout -> fd/1

$ ls -l /dev/fd/1
crw-rw-rw-  1 root  wheel  0x18 May  8 21:35 /dev/fd/1

5

(Майже) все - це файл, але не все - звичайний файл. Немає сенсу викликати текстовий редактор на щось, що є спеціальним файлом, таким як каталог, мережевий сокет, послідовний порт тощо.

Файл /dev/stdoutможе бути одним із кількох речей залежно від варіанту unix:

  • "спеціальний" файл, як правило, символьний пристрій;
  • символічне посилання "магія", яке вказує на файл, який відкриває процес, що має доступ до цього дескриптора;
  • символічне посилання на одне із зазначених вище.

У будь-якому випадку, відкриваючи /dev/stdoutта подібні файли, створюється новий дескриптор файлів, пов'язаний з тим самим файлом, який програма вже відкрила в дескрипторі файлів 1. "Стандартний вихід" означає дескриптор файлу 1, і це лише умова використання цього дескриптора файлів для виводу - ядро ​​не хвилює.

Коли ви запускаєте програму в терміналі, всі три стандартні дескриптори (0 = стандартний вхід, 1 = стандартний вихід, 2 = стандартна помилка) відкриваються на термінальному пристрої. Читання з цього пристрою повертає символи, введені користувачем, а запис на цей пристрій відображає текст у вікні терміналу. (Немає стандартного способу для даного термінального пристрою зчитувати вихід, який він відображає, або вводити в нього вхід.)

Коли ви запускаєте cat /dev/stdout, це робить те саме, що cat /dev/stdinабо cat /dev/stderr, тому що ці три дескриптори файлів підключені до одного файлу: він повідомляє catчитати з терміналу. Ось що catі без аргументів.

Якщо ви бігли cat /dev/stdout >foo, то /dev/stdoutпосилалися б на файл foo- ця команда еквівалентна cat foo >foo. Залежно від catреалізації, вона може або помилитися (версія GNU скаржиться на те, що "вхідний файл є вихідним файлом"), або може нічого не робити, тому що читає з fooпорожнього файлу ( >fooпросто усічений). З версією cat, яка не виявляє цей особливий випадок, якщо fooвін не порожній, тоді cat /dev/stdout >>fooабо еквівалент cat foo >>fooдодає вміст файлу до себе на невизначений час.

Під час запуску vim /dev/stdoutвін скаржиться, оскільки не знає, як редагувати термінал (це просто не має сенсу).


2

catі tailшукають необов’язковий вміст з подальшим закінченням файлу. /dev/stdoutзалишається відкритим, так catі tailпросто продовжуйте дивитися.

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