Яка різниця між 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?

Відповіді:


21

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

Якщо першим словом у командному рядку є програма, розміщена в спеціальній папці (в основному визначається PATH), і більше ніяких спеціальних символів не дається (залежно від оболонки, яку ви використовуєте), всі наступні слова, розділені пробілами чи вкладками, передаються в програма в спеціальній формі, тобто масив. З кожним словом як одним елементом у масиві.

Як програма, яку ви збираєтеся викликати, інтерпретує аргументи (розташовані в масиві), залежить від того, як вона запрограмована. Існує кілька квазі стандартів того, як повинен виглядати синтаксис аргументів, але загалом програміст повністю вільний. Таким чином, перший аргумент можна інтерпретувати як ім'я файлу або все, що думає програміст під час написання програми.

У випадку, якщо ви додасте спеціальний символ <або >у свій командний рядок, оболонка не додає, <а >також наступні слова до масиву, який буде переданий програмі. З <або >дали запуски оболонки , щоб зробити модні речі, які підтримуються нижчого ядром (ключовим словом трубопроводу ). Щоб зрозуміти, що відбувається, ви повинні зрозуміти, що 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і аргументи командного рядка інтерпретуються все до відповідного розробника.

Я сподіваюся, що моя відповідь могла б прояснити речі.


Дякую за це детальне пояснення. У ваших останніх пунктах, ви згадали використання man -l - < file_nameзробити manтлумачить в STDINякості аргументів, але вона не в моїй системі з STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang

Ласкаво просимо. Але я не згадував, що принаймні моя версія man( man-db ) читає аргументи STDINз поданими аргументами, -lза якими слідує -. Він просто інтерпретує дані STDINяк доменну сторінку. Для більш детальних пояснень дійсних аргументів та того, як вони трактуються, ви повинні ознайомитись зі сторінкою відповідної програми. У вашому випадку проконсультуйтеся man man. Можливо, є подібний варіант для вашого man. Якщо ви хочете прочитати аргументи командного рядка для певної програми STDIN xargs(на зразок згаданого вище) - це шлях.
користувач1146332

Я man manі знаходжу в моїй ОС це не підтримує. У всякому разі, дякую за цю декларацію цих двох понять для мене.
steveyang

Я відредагував вашу відповідь, щоб вона містила фактично корисні посилання замість lmgtfy. Розміщення lmgtfy-посилань - це 1) грубість, 2) недоброзичливість та 3) дійсно нахмуреність на сайтах SE. Будь ласка, надайте посилання або не, але якщо ви вирішите це зробити, надайте посилання на фактичну інформацію, а не на саркастичний спосіб показувати комусь, як її знайти.
terdon

12

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

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

Якщо вам справді потрібна така поведінка, ви можете скористатися xargs, що перетворює файл в аргументи командного рядка:

$ xargs man < file_name

Або просто вставте catвиклик у manвиклик:

$ man $(cat file_name)

В bash, ви можете використовувати man $(<file_name).
Йорданм

Re: "Я не думаю, що будь-який інший інструмент працює таким чином" - Perl's (<>)в циклі буде робити STDINабо аргументи командного рядка як імена файлів ...
Аарон Д. Мараско,

@ AaronD.Marasco Я мав на увазі, що жоден інструмент не бере аргументу чи читає ім'я файлу зі stdin та читає аргумент із цього файлу
Michael Mrozek

@MichaelMrozek Дякую за це роз’яснення. Мета, яку я використав man < file_name- допомогти зрозуміти ці два поняття. Читаючи вам пояснення, реалізацію вирішує автор команди. Тож якщо я маю рацію, findаргументи бере, а не обробляє STDIN?
steveyang
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.