Как действует этот стандартный оператор ввода (0

Вопрос или проблема

Предположим, что в Linux есть два файла. fileA и fileB, оба с различными списками фруктов. Я применяю следующие команды:

diff fileA fileB > file.diff

Затем я выполняю следующую команду:

patch fileA 0< file.diff

Вышеуказанная команда применяет патчи (исправляет ошибки) в оригинальном файле (fileA) из входных данных, предоставленных file.diff, и отправляет вывод в fileA (это мое понимание, возможно, я ошибаюсь). Другими словами, fileA и fileB совпадают.

“0<” является символом перенаправления для стандартного ввода (насколько я понимаю). Теперь, поскольку стандартный ввод — это клавиатура, разве команда patch не должна считывать с клавиатуры, а не из file.diff? Как работает указанная команда?

Команды ниже одинаковы. 1 является значением по умолчанию и поэтому может быть опущено. По сути, стандартный вывод из diff перенаправляется с экрана в файл file.diff.

diff fileA fileB > file.diff
diff fileA fileB 1> file.diff

Команды ниже одинаковы. 0 является значением по умолчанию и поэтому может быть опущено. По сути, стандартный ввод для patch перенаправляется с клавиатуры, чтобы поступать из файла file.diff.

patch fileA 0< file.diff
patch fileA < file.diff

Я попытаюсь объяснить следующее. Когда я ввожу команду tty, я получаю следующий вывод:

/dev/pts/0

Это означает, что терминальному окну присвоено имя файла /dev/pts/0. Оба стандартных ввода и вывода назначены именами файлов /dev/fd/0 и /dev/fd/1 соответственно.

Команда ниже проверяет, имеют ли стандартный ввод (/dev/fd/0) и терминальное окно (/dev/pts/0) одинаковые значения устройства и inode. Другими словами, тест, чтобы увидеть, являются ли они одинаковыми. В этом случае вывод — true.

if [[ /dev/fd/0 -ef /dev/pts/0 ]]; then echo "true"; else echo "false"; fi

Команда ниже проверяет, имеют ли стандартный ввод (/dev/fd/0) и файл file.diff одинаковые значения устройства и inode. В этом случае вывод — false.

if [[ /dev/fd/0 -ef file.diff ]]; then echo "true"; else echo "false"; fi

Однако, если стандартный ввод перенаправлен из файла file.diff, как показано ниже, вывод будет true.

if [[ /dev/fd/0 -ef file.diff ]]; then echo "true"; else echo "false"; fi < file.diff

“0<” является символом перенаправления для стандартного ввода (насколько я понимаю). Теперь, поскольку стандартный ввод — это клавиатура, разве команда patch не должна считывать с клавиатуры, а не из file.diff? Как работает указанная команда?

Нет. Стандартный ввод подключен к клавиатуре (или, точнее, к устройству ‘tty’, через которое ОС предоставляет ввод с клавиатуры). В любое время соединение может быть закрыто, и вместо него может быть открыто что-то другое – термин “стандартный ввод” относится к конкретному “слоту” подключения, а не к месту его направления. (Поэтому он называется “стандартный ввод”, а не “ввод с клавиатуры”.)

Цифры не просто синтаксис оболочки; они представляют то, как сами программы работают с открытыми файлами. В каждом процессе каждый “открытый файл” представлен числом (дескриптор файла, или как его именуют в Windows, handle). По стандартной конвенции, какой бы открытый файл ни был назначен дескриптору файла 0, он является “стандартным вводом”.

Если вы запускаете программу из терминала, то “tty” терминала предварительно открывается как FD 0 – или, скорее, унаследован от оболочки, где он уже был открыт – и, следовательно, это стандартный ввод программы. (То же самое для 1, который является стандартным выводом, и 2, который является stderr.) Тогда программа ‘diff’ сама должна открыть некоторые файлы, так что она выполнит open("fileA", ...), и fileA будет открыт как FD 3 и так далее.

Но так же, как программа может закрыть любой файл, который она сама открыла (например, она может закрыть fileA, выполняя close(3)), она также может выполнить close(0), чтобы закрыть свой стандартный ввод и открыть что-то еще на его месте; до тех пор пока вновь открытый файл получает файловый дескриптор 0, он по определению является “стандартным вводом”.

Оболочка может сделать то же самое непосредственно перед тем, как запустить программу. Использование <file.diff или 0<file.diff означает, что оболочка закроет свой оригинальный дескриптор файла ввода close(0) и откроет файл open("file.diff") в качестве нового FD 0, который затем становится новым стандартным вводом, наследуемым программой ‘diff’.

Ответ или решение

Вопрос, касающийся работы стандартного оператора ввода в Linux, особенно символа "0<", часто вызывает недоумение у пользователей, особенно тех, кто привык думать о стандартном вводе как исключительно о вводе с клавиатуры. Давайте рассмотрим, как работает этот механизм, используя теорию, примеры и их конкретное применение.

Теория:

Стандартный ввод (stdin) в современных операционных системах часто ассоциируется с клавиатурой пользователя. Однако на практике stdin — это нечто большее, чем просто ввод с клавиатуры. В UNIX-подобных системах, таких как Linux, стандартный ввод, стандартный вывод (stdout) и стандартная ошибка (stderr) представлены в виде файловых дескрипторов. Они имеют численные идентификаторы: 0 для stdin, 1 для stdout и 2 для stderr. Эти дескрипторы позволяют оболочкам и программам динамически перенаправлять данные из одного источника в другой.

Конструкция "0<" в командной строке указывает на перенаправление стандартного ввода. В то время как стандартный ввод по умолчанию подключен к клавиатуре через терминальный интерфейс (‘tty’), этот ввод можно заменить данными из файла. Это позволяет программам, таким как patch, использовать содержимое файла вместо данных, вводимых пользователем с клавиатуры.

Пример:

Рассмотрим конкретный пример с использованием файлов fileA и fileB, содержащих списки фруктов. Сначала мы используем команду diff:

diff fileA fileB > file.diff

Эта команда сравнивает содержимое двух файлов, отправляя вывод (различия) в файл file.diff. Здесь используется оператор ">", который перенаправляет стандартный вывод в файл. Этот же принцип применим и к перенаправлению stdin. Далее используется команда:

patch fileA 0< file.diff

Здесь оператор "0<" перенаправляет стандартный ввод команды patch, означая, что программа будет считывать данные из файла file.diff, а не с клавиатуры. Общепринято считать, что "0<" аналогично просто "<", так как числовое обозначение (0 для stdin) опционально.

Применение:

В чем практическая значимость? Во-первых, понимание этого механизм позволяет автоматизировать обновления и изменения в файлах без необходимости пользовательского ввода. Например, при разработке программного обеспечения или администрировании сервера, автоматизация процессов коррекции данных через патчи помогает поддерживать код в актуальном состоянии.

Кроме того, возможность перенаправления стандартного ввода из файла делает Shell-скрипты более гибкими и мощными. Можно, например, заранее сформировать различные патчи для разных наборов данных и применять их по мере необходимости, что значительно экономит время и ресурсы.

Дополнительно, понимание работы с файловыми дескрипторами в Linux расширяет навык работы с файловой системой и взаимодействие с различными устройствами как с файлами. В пределах процесса, любая сущность, открытая как файл, может быть использована как поток данных, будь то внутренняя работа программы или взаимодействие с внешними устройствами.

Подводя итог, перенаправление стандартного ввода — это фундаментальный аспект UNIX-подобных систем, который улучшает управление процессами и оптимизирует автоматизацию задач, связанных с обработкой данных. Для ИТ-специалистов овладение этими навыками является неотъемлемой частью профессиональной компетенции, обеспечивающей эффективное использование командной строки Linux и оболочки Bash в частности.

Оцените материал
Добавить комментарий

Капча загружается...