bashunixstdinwc

Command `wc` with argument files and standard input redirection


I have come across the command line wc < f1 f2 and it's not clear for me what is happening under the hood:

$ echo -n 'a' > f1
$ wc f1
0 1 1 f1

$ echo -n 'bb' > f2
$ wc f2
0 1 2 f2

$ wc < f1 f2
0 1 2 f2

Here the standard input of wc is being redirected to file f1, but I'm also passing file f2 as argument. The output I get is as if I had typed wc f2, i.e.., the standard input is not considered by wc, it seems.

Is wc discarding its standard input (wherever it points to) when it also gets passed a file as argument?

Is wc internally still handling two file descriptors, one for standard input and another for the file it's being passed as argument, or is it the kernel to "unplug" the standard input file descriptor from file f1 and plug it to file f2 later, in this case?

What else, or what IS actually happening, in a command line like wc < f1 f2?

I am using the Bash shell in Ubuntu 22.04.

Thanks


Solution

  • Here the standard input of wc is being redirected to file f1, but I'm also passing file f2 as argument. The output I get is as if I had typed wc f2, i.e.., the standard input is not considered by wc, it seems.

    Yes. wc reads its standard input if and only if either

    Note that multiple inputs can be specified on the command line, - among them, though it is not useful to specify - more than once.

    This is all documented in the manual, albeit a but more concisely.

    Is wc discarding its standard input (wherever it points to) when it also gets passed a file as argument?

    No, it's just not reading anything from its standard input in that case. And that's usually what you want when you ask it to read from a file. Rarely do you want it to try to read interactive input from the keyboard, for example, but that's what its stdin is connected to when you run wc interactively and do not redirect.

    Is wc internally still handling two file descriptors, one for standard input and another for the file it's being passed as argument, or is it the kernel to "unplug" the standard input file descriptor from file f1 and plug it to file f2 later, in this case?

    That's unspecified, but certainly not a matter of kernel behavior. What I would expect, especially in light of wc's behavior around multiple filename arguments and the - argument, is that wc opens and processes each named file in turn, or uses the stdin provided by the system when the current argument is -. I would be surprised to find that it did any internal I/O redirection.

    What else, or what IS actually happening, in a command line like wc < f1 f2

    The redirection < f1 is parsed by the shell and processed separately from the command line arguments. The shell performs the corresponding redirection before handing off control to wc. The redirection operator tokens do not constitute command-line arguments themselves, so the wc command sees only the effect of the redirection, but not the redirection operator itself. Among the consequences is that wc < f1 f2 is functionally equivalent to wc f2 < f1.

    wc, for its part, behaves as documented. At least one filename argument having been specified, it counts the contents of the indicated file only. If you want it to count first the data redirected from its standard input and then the contents of file f2, then that would be

    wc - f2 < f1
    

    (for example).