gambarimas87
gambarimas87

Reputation: 147

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

Upvotes: 2

Views: 220

Answers (3)

John Bollinger
John Bollinger

Reputation: 181179

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

  • no input file is specified on the command line, OR
  • the command-line argument - is provided, which explicitly represents the standard input.

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 bit 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, 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).

Upvotes: 2

Bodo
Bodo

Reputation: 9875

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

Ignoring stdin if file arguments are specified is normal behavior for many commands. This is done by the program itself, i.e. by the wc program in this case.

Often you can use - as a command line argument to use stdin like an ordinary file specified on the command line.

This behavior is defined by the POSIX specification for wc. My understanding of "...and the implementation treats the '-' as meaning standard input" is that it depends on the implementation if - means standard input or a file named -.

Citing https://man7.org/linux/man-pages/man1/wc.1p.html

STDIN

The standard input shall be used if no file operands are specified, and shall be used if a file operand is '-' and the implementation treats the '-' as meaning standard input. Otherwise, the standard input shall not be used. See the INPUT FILES section.

Example:

$ wc foo bar
 1  1  4 foo
 2  2  8 bar
 3  3 12 total

$ wc foo < bar
1 1 4 foo

$ wc < foo bar
2 2 8 bar

$ wc - bar < foo
 1  1  4 -
 2  2  8 bar
 3  3 12 total

$ wc < foo - bar
 1  1  4 -
 2  2  8 bar
 3  3 12 total

$ echo foo | wc - bar
      1       1       4 -
      2       2       8 bar
      3       3      12 total

Upvotes: 1

KamilCuk
KamilCuk

Reputation: 141698

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

wc < f1 f2 executes wc f2 <f1 - executes command wc with one argument f2 and redirects file f1 to standard input.

wc f2 just prints the counts for file f2. Nothing happens to standard input.

Is wc discarding its standard input

No, there is no "discarding", there is "ignoring". wc does not touch standard input at all. "Discarding" would imply the standard input is fully read after wc exits, but it is not.

Is wc internally still handling two file descriptors

No, wc is "handling" only f2 file - opening and reading it. You can see what system calls wc is doing by using strace wc f2.

is it the kernel to "unplug" the standard input file descriptor from file f1 and plug it to file f2 later, in this case?

There is no "unplugging".

Upvotes: 1

Related Questions