What's the difference between STDIN and arguments passed to command?
Solution 1
Your question is closely related to how the shell you are using parses user input on the command line.
If the first word on the command line is a program, located in a special folder (mostly defined by PATH
) and no more special characters are given (depends of the shell you are using), all subsequent words separated by spaces or tabs are passed to the program in a special form i.e. an array. With each word as one element in the array.
How the program, you are going to invoke interprets the arguments (located in the array) depends on how it is programmed. There are some quasi standards of how the syntax of the arguments should look like but in general the programmer is entire free. So the first argument can be interpreted as a name of a file or whatever the programmer thoughts of at the time he wrote the program.
In the case you add the special character <
or >
to your command line, the shell dosn't append <
and >
nor subsequent words to the array that will be passed to the program. With <
or >
given the shell starts to make fancy things, supported by the underlying kernel (keyword piping). To grasp what's going on you must understand what STDIN
and STDOUT
(since it's not immediately related i omit STDERR
) are.
Everything visible you see on your terminal (in most cases a part of your display) is either written by the shell or any other program you have invoked previously to a special file (in unix everything is a file). This file has a special id and is called STDOUT
. If a program wants to read data from the keyboard it dosn't poll the keyboard directly (at least in most cases) but reads from a special file called STDIN
. Internally this file is connected to your standard input device, your keyboard in most cases.
If the shell reads <
or >
in a parsed command line it manipulates STDIN
or STDOUT
in a particular kind for the time the corresponding program is running. STDIN
and STDOUT
dosn't point to the terminal or the standard input device any longer but rather to the subsequent filename on the command line.
In the case of the two lines
cat file_name
cat < file_name
the observed behavior is identical because the corresponding developer makes cat
to either read data from STDIN
or read the data from the file, whose name is given as the first command line argument (which is the first element in the array the shell passes to cat
). Subsequently cat
writes the whole content of file_name
or STDIN
to the terminal since we don't instruct the shell to manipulate STDOUT
. Remember that in the second line your shell manipulates STDIN
in this way, that it doesn't point to your standard input device anylonger but points to a file called file_name
in your current working directory.
In the other case of the line
man < file_name
man
is not meant to read anything from STDIN
if it's called with no argument i.e. an empty array. So the line
man < file_name
equals
man
For example man
will read something from STDIN
, too if you pass -l -
to man
. With this option given on the command line you can display the content of anything man
reads from STDIN
on your terminal. So
man -l - < file_name
would work also (but be careful man
is not just a pager but also parses the input of the file and so the file content and the displayed content could differ).
So how STDIN
, STDOUT
and the command line arguments are interpreted is all up to the corresponding developer.
I hope my answer could clear things up.
Solution 2
They're completely different. Command-line arguments are passed to the program in an array and it can do what it wants with them; stdin is an input stream the program has to request data from. Programs that process files often choose to support both, but they have to do so manually -- they check if a filename was passed as a command-line argument, and if not they read from stdin instead
You seem to be expecting man
to read stdin to find the man page it should display, which would be a really strange behavior; when would you ever use that? The fact that cat
displays its stdin is an artifact of the fact that it does nothing else; I don't think any other tool works that way. For example, grep
can take a filename or read from stdin
, but it processes the data on stdin
, it doesn't read a filename from stdin
and then open it
If you really do need this behavior, you could use xargs
, which converts a file to command-line arguments:
$ xargs man < file_name
Or just embed a cat
call within the man
call:
$ man $(cat file_name)
Related videos on Youtube
steveyang
Updated on September 18, 2022Comments
-
steveyang almost 2 years
I could use the either form to execute the
cat
method:cat file_name cat < file_name
The result is the same
Then I want to execute
man
in the format ofstdin
man < file_name
While
file_name
contains:# file_name cat
But it pops up
What manual page do you want?
instead of executeman cat
.I want to know why
cat
could acceptstdin
as arguments butman
cannot. And what's the difference between command line arguments andstdin
? -
jordanm almost 12 yearsIn bash, you can use
man $(<file_name)
. -
Aaron D. Marasco almost 12 yearsRe: "I don't think any other tool works that way" - Perl's
(<>)
in a loop will doSTDIN
or command-line arguments as filenames... -
Michael Mrozek almost 12 years@AaronD.Marasco I meant no tool either takes an argument or reads a filename from stdin and reads the argument from that file
-
steveyang almost 12 years@MichaelMrozek Thanks for this clarification. The purpose I used
man < file_name
is to help myself understand this two concepts. Reading you explanation, the implementation is decided by the command author. So if I under right, thefind
takes arguments rather processes STDIN? -
steveyang almost 12 yearsThanks for this detailed explanation. For your last few paragraphs, you mentioned use
man -l - < file_name
to makeman
interpretsSTDIN
as arguments, but it fails in my system with theSTDERR
:man -l - < tee man: invalid option -- l man, version 1.6c
-
user1146332 almost 12 yearsYou're welcome. But i didn't mention that at least my version of
man
(man-db) reads arguments fromSTDIN
with the given arguments-l
followed by-
. It just interprets data fromSTDIN
as a man page. For more detailed explanations of valid arguments and how they are interpreted you have to consult the man page of the related program. In your case consultman man
. Maybe there is a similar option for yourman
. If you want to read command line arguments for a specific program fromSTDIN
xargs
(like mentioned above) is the way to go. -
steveyang almost 12 yearsI
man man
and find the one in my OS doesn't support it. Anyway, thanks for this declaration of these two concepts for me. -
terdon almost 10 yearsI edited your answer so it contains actually useful links instead of lmgtfy. Posting lmgtfy links is 1) rude, 2) unhelpful and 3) really frowned upon on the SE sites. Either provide a link or don't but if you choose to do so, provide a link to actual information and not to a sarcastic way of showing someone how to find it.
-
Admin about 2 yearsLittle known fact :
cat <file -n
is actually equivalent tocat -n <file
(I'm reacting to « the shell do[e]sn't append<
and>
nor subsequent words to the array [...] »)