Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash "wc -l" command output differs if call or through tee

When I issued two equivalent commands in Bash I got different output (from "wc -l" command), see below:

root@devel:~# ls /usr/bin -lha | tee >(wc -l) >(head) > /dev/null
total 76M
drwxr-xr-x  2 root root      20K Nov 11 18:58 .
drwxr-xr-x 10 root root     4.0K Oct  8 15:31 ..
-rwxr-xr-x  1 root root      51K Feb 22  2017 [
-rwxr-xr-x  1 root root       96 Jan 19  2017 2to3-3.5
-rwxr-xr-x  1 root root      23K Mar 22  2017 addpart
lrwxrwxrwx  1 root root       26 May 10  2017 addr2line -> x86_64-linux-gnu-    addr2line
lrwxrwxrwx  1 root root        6 Dec 13  2016 apropos -> whatis
-rwxr-xr-x  1 root root      15K Sep 13 19:47 apt
-rwxr-xr-x  1 root root      79K Sep 13 19:47 apt-cache
137
root@devel:~# ls /usr/bin -lha | wc -l
648

what am I missing?

it's strange, but when I call it this way it gets even stranger output:

root@devel:~# ls /usr/bin -lha | tee >(wc) >(wc) > /dev/null
648    6121   39179
648    6121   39179
root@devel:~# ls /usr/bin -lha | tee >(wc) >(wc) > /dev/null
648    6121   39179
648    6121   39179
root@devel:~# ls /usr/bin -lha | tee >(wc) >(wc -l) > /dev/null
648
root@devel:~#     648    6121   39179

seems like commands running asynchronously and ends in different time... or what it can be?

like image 614
urusai_na Avatar asked Nov 12 '17 19:11

urusai_na


People also ask

What who wc l command will do?

wc -l : Prints the number of lines in a file. wc -w : prints the number of words in a file. wc -c : Displays the count of bytes in a file.

What does wc output?

The wc utility displays the number of lines, words, and bytes contained in each input file (or standard input, by default) to standard output. A line is defined as a string of characters delimited by a newline character. A word is defined as a string of characters delimited by white space characters.

When to use tee command in Linux?

The tee command, used with a pipe, reads standard input, then writes the output of a program to standard output and simultaneously copies it into the specified file or files. Use the tee command to view your output immediately and at the same time, store it for future use.

Which of the following is the default output of the wc command in Linux?

Description. wc stands for word count is a command in Unix and Unix-like operating systems. It is mainly used for counting purpose. By default it displays four-columnar output.


1 Answers

Simple answer:

how to fix:

ls /usr/bin -lha | tee --output-error=exit-nopipe >(wc -l) >(head) > /dev/null

Details:

The command head only prints the head of input, so it can finish its job as long as it gets enough input, then exits without waiting for all input.

So let's replace command head with the simple "head".

ls /usr/bin -lha | tee >(wc -l) >(read l; echo $l) > /dev/null

The simple "head" will read only one line, then exit, which causes that the pipe file gets closed immediately before tee finishes transferring all data to it.

So no doubt, you'll get same result with the simple "head". wc still prints wrong number.

The root reason of your issue, I think you can conclude yourself, is that one of the output pipes of tee is closed earlier, tee hits a write error, and then stops writing to other output files.

After understanding the root reason, I think it would be very easy for you to understand the following section in man page.

MODE determines behavior with write errors on the outputs:
   'warn' diagnose errors writing to any output

   'warn-nopipe'
          diagnose errors writing to any output not a pipe

   'exit' exit on error writing to any output

   'exit-nopipe'
          exit on error writing to any output not a pipe

   The  default MODE for the -p option is 'warn-nopipe'.  The default operation
   when --output-error is not specified, is to exit immediately on error writing to
   a pipe, and diagnose errors writing to non pipe outputs.

Some extra words

Actually if you replace >(wc -l) with a regular file in your problematic command line, you will find the file size will always be 16384 or 20480 or 32768 or 36864 or 28672 or ..., all of which are the multiple of 4096. (The writing to the regular file is incomplete because tee aborts earlier. If the writing was complete, the file size would be any value.)

4096 is the value of PIPE_BUF for most UNIX-like system. If you know what PIPE_BUF is, you will easily understand why the file size is always the multiple of 4096.

like image 133
Bruce Avatar answered Oct 23 '22 04:10

Bruce