Search code examples
bashunixpipetee

Counting and recording the number of arguments passed in a pipe


Is there any way of counting and recording the number of arguments passing through a pipe? I am piping a values from a file of unknown length. I can dump the number to STDOUT using tee but cannot get them into a variable:

seq 10 | tee >(wc -l) | xargs echo 

I'm interested in whether this is possible for aesthetics and my own understanding rather than some roundabout alternative such as rescanning the (non-txt) file_of_unknown length twice, or writing to an actual file then reading back in, etc.

Thanks!


Solution

  • A component in a pipeline (such as the tee in the OP) is executed in a subshell. Consequently, it cannot modify the parent shell's variables. That's a general rule about subshells and shell variables. Every shell has its own variables; when a (sub)shell is started, (some of) the parent shell's variables are copied into the child shell, but there is no link between variables in the parent and variables in the child.

    You can communicate between subshells using pipes, but in a pipeline you are already doing that so it will be difficult to coordinate another layer, although it's not impossible. The aesthetics are not great, though.

    So basically your best approach is exactly the one you explicitly discard, "writing to an actual file then reading back in". That's simple and reliable, and it's quite fast, particularly if the file is on an in-memory temporary filesystem (see tmpfs).

    By the way, xargs normally splits input lines at whitespace to generate arguments, so in general the number of arguments it receives is not the same as the number of lines it reads.