简体   繁体   中英

In a shell (bash) How can I execute more than one command in a pipeline?

I'm trying pipe the output of an awk command through more than one command at once in a Bash shell, following my knowledge I'm coming up with this:

awk '$13 ~ /type/ {print $15}' filename.txt | (wc -l || sort -u)

I want the result of the awk command to be both counted AND sorted, how can I accomplish that? Even with && command it doesn't work, it does execute the first command and then exits. I guess it is my knowledge of bash which is failing.

Thanks in advance.

If you want to send output to two different commands in a single line, you'll need to do process substituion.

Try this:

awk '$13 ~ /type/ {print $15}' filename.txt | tee >(wc -l >&2) | sort -u

This outputs the line count on stderr and the sorted output on stdout. If you need the line count on stdout, you can do that leave off the >&2 , but then it will be passed to the sort call and (most likely) sorted to the top of the output.

EDIT: corrected description of what happens based on further testing.

in that case, do your counting in awk , why the need for pipes? don't make it more complicated

awk '$13 ~ /type/ {print $15;c++}END{print c} ' filename.txt | sort -u

If the size in the output is not too large to fit in memory and you don't need the wc and sort commands to work in parallel for performance reasons, here's a relatively simple solution:

output=$(awk '$13 ~ /type/ {print $15}' filename.txt; echo a)
printf "%s" "${output%a}" | sort -u
printf "%s" "${output%a}" | wc -l

That complication with the the extra a is in case the awk command might print some empty lines at the end of the input, which the $() construct would strip. You can easily choose which of sort or wc should appear first.


Here's a way that works with any POSIX shell (ash, bash, ksh, zsh, ...) but only on systems that have /dev/fd (which includes reasonably recent Linux, *BSD and Solaris). Like Walter's similar construction using the simpler method available in bash, ksh93 and zsh , the output of wc and the output of sort may be intermixed.

{
  awk '$13 ~ /type/ {print $15}' filename.txt |
  tee /dev/fd3 |
  wc -l
} 3>&1 1>&3 | sort -u

If you both need to deal with intermediate output that doesn't comfortably fit in memory and don't want to have the output of the two commands intermixed, I don't think there's an easy way in a POSIX shell, though it should be doable with ksh or zsh coprocesses.

I think the bigger question is: what are you expecting the output to be?

If you're trying to do two things, then do two things:

awk '$13 ~ /type/ {print $15}' filename.txt > tempfile
wc -l < tempfile
sort -u < tempfile
rm tempfile

You want to use named pipes created with mkfifo in combination with tee. An example is at http://www.softpanorama.org/Tools/tee.shtml

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM