В чем разница между STDIN и аргументами, передаваемыми в команду?

16

Я мог бы использовать любую форму для выполнения catметода:

cat file_name
cat < file_name

Результат тот же

Тогда я хочу выполнить manв форматеstdin

man < file_name

Пока file_nameсодержит:

# file_name
cat

Но он появляется What manual page do you want?вместо выполнения man cat.

Я хочу знать, почему catмог принять в stdinкачестве аргументов, но manне могу. И в чем разница между аргументами командной строки и stdin?

steveyang
источник

Ответы:

21

Ваш вопрос тесно связан с тем, как используемая оболочка анализирует пользовательский ввод в командной строке.

Если первое слово в командной строке - это программа, расположенная в специальной папке (в основном определяемой как PATH), и больше не вводятся специальные символы (в зависимости от используемой вами оболочки), все последующие слова, разделенные пробелами или символами табуляции, передаются в программа в специальной форме т.е. массив. С каждым словом в качестве одного элемента в массиве.

То, как программа, которую вы собираетесь вызывать, интерпретирует аргументы (расположенные в массиве), зависит от того, как она запрограммирована. Существует несколько квази-стандартов того, как должен выглядеть синтаксис аргументов, но в целом программист полностью свободен. Таким образом, первый аргумент может быть интерпретирован как имя файла или то, о чем думал программист во время написания программы.

В случае, если вы добавите специальный символ <или >в командную строку, оболочка не добавит <и >ни последующие слова в массив, который будет передан программе. При наличии <или >задании оболочка начинает делать причудливые вещи, поддерживаемые базовым ядром (ключевое слово piping ). Чтобы понять, что происходит, вы должны понимать, что STDINи STDOUT(поскольку это не связано непосредственно, я опускаю STDERR).

Все, что вы видите на своем терминале (в большинстве случаев это часть вашего дисплея), либо написано оболочкой, либо любой другой программой, которую вы ранее вызывали, в специальный файл (в unix все является файлом ). Этот файл имеет специальный идентификатор и называется STDOUT. Если программа хочет считывать данные с клавиатуры, она не запрашивает клавиатуру напрямую (по крайней мере, в большинстве случаев), а читает из специального файла с именем STDIN. Внутренне этот файл подключен к вашему стандартному устройству ввода, в большинстве случаев к вашей клавиатуре.

Если оболочка читает <или >в разобранной командной строке, она манипулирует STDINили STDOUTв определенном виде во время выполнения соответствующей программы. STDINи больше не STDOUTуказывает на терминал или стандартное устройство ввода, а на последующее имя файла в командной строке.

В случае двух линий

cat file_name
cat < file_name

наблюдаемое поведение идентично, потому что соответствующий разработчик заставляет catлибо читать данные, STDINлибо читать данные из файла, чье имя задается в качестве первого аргумента командной строки (который является первым элементом в массиве, в который оболочка передает cat). Впоследствии catзаписывает весь контент file_nameили STDINв терминал, так как мы не инструктируем оболочку манипулировать STDOUT. Помните, что во второй строке ваша оболочка манипулирует STDINтаким образом, что она больше не указывает на ваше стандартное устройство ввода, а указывает на файл, называемый file_nameв вашем текущем рабочем каталоге.

В другом случае линии

man < file_name

manне предназначен для чтения чего-либо, STDINесли он вызывается без аргумента, т.е. с пустым массивом. Итак, линия

man < file_name

равно

man

Например, manбудет читать что-то из STDINтоже, если вы переходите -l -к man. С помощью этой опции, заданной в командной строке, вы можете отображать содержимое всего, что manсчитывается с STDINвашего терминала. Так

man -l - < file_name

будет также работать (но будьте осторожны, manэто не только пейджер, но и анализирует входные данные файла, поэтому содержимое файла и отображаемое содержимое могут отличаться).

Так как STDIN, STDOUTи аргументы командной строки интерпретируются все до соответствующего разработчика.

Я надеюсь, что мой ответ может прояснить ситуацию.

user1146332
источник
Спасибо за это подробное объяснение. В ваших последних нескольких абзацах вы упомянули использование man -l - < file_nameдля создания manинтерпретаций в STDINкачестве аргументов, но в моей системе это не STDERRman -l - < tee man: invalid option -- l man, version 1.6c
помогло
Пожалуйста. Но я не упомянул, что, по крайней мере, моя версия man( man-db ) читает аргументы STDINс заданными аргументами, -lза которыми следует -. Он просто интерпретирует данные STDINкак справочную страницу. Для более подробного объяснения действительных аргументов и того, как они интерпретируются, вы должны обратиться к странице справки соответствующей программы. В вашем случае проконсультируйтесь man man. Может быть, есть аналогичный вариант для вас man. Если вы хотите прочитать аргументы командной строки для конкретной программы STDIN xargs(как упоминалось выше), это путь.
user1146332
Я man manи нахожу тот, в моей ОС не поддерживает его. В любом случае, спасибо за эту декларацию этих двух концепций для меня.
Steveyang
Я отредактировал ваш ответ, чтобы он содержал полезные ссылки вместо lmgtfy. Размещение ссылок lmgtfy: 1) грубо, 2) бесполезно и 3) действительно осуждается на сайтах SE. Либо предоставьте ссылку, либо нет, но если вы решите это сделать, укажите ссылку на актуальную информацию, а не на саркастический способ показать кому-то, как ее найти.
Terdon
12

Они совершенно разные. Аргументы командной строки передаются программе в виде массива, и она может делать с ними все, что захочет; stdin - входной поток, из которого программа должна запрашивать данные. Программы, обрабатывающие файлы, часто выбирают поддержку обоих, но они должны делать это вручную - они проверяют, было ли передано имя файла в качестве аргумента командной строки, и если нет, то вместо этого читают из stdin

Вы, кажется, ожидаете manпрочитать stdin, чтобы найти страницу руководства, которую он должен отобразить, что было бы очень странным поведением; когда бы ты это использовал? Тот факт, что он catотображает свой стандарт, является артефактом того, что он больше ничего не делает; Я не думаю, что какой-либо другой инструмент работает таким образом. Например, grepможет взять имя файла или прочитать его stdin, но обрабатывает данные stdin, не читает имя файла stdinи затем открывает его

Если вам действительно нужно это поведение, вы можете использовать xargs, который преобразует файл в аргументы командной строки:

$ xargs man < file_name

Или просто вставьте catзвонок в manзвонок:

$ man $(cat file_name)
Михаил Мрозек
источник
В Bash вы можете использовать man $(<file_name).
Иордания
Re: «Я не думаю, что какой-либо другой инструмент работает таким образом» - Perl (<>)в цикле будет делать STDINили аргументы командной строки в качестве имен файлов ...
Аарон Д. Мараско
@ AaronD.Marasco Я имел в виду, что ни один инструмент не принимает аргумент или не читает имя файла из stdin и не читает аргумент из этого файла
Майкл Мрозек
@MichaelMrozek Спасибо за это разъяснение. Цель, которую я использовал, man < file_nameсостоит в том, чтобы помочь себе понять эти два понятия. Читая вам объяснение, реализация решается автором команды. Так что если я прав, то findаргументы скорее обрабатывают STDIN?
Steveyang