How to merge and pipe results from two different commands to single command?

I want merge (union) output from two different commands, and pipe them to a single command.

A silly example:

Commands I want to merge the output:

cat wordlist.txt
ls ~/folder/*

into:

wc -l

In this example, if wordlist.txt contains 5 lines and 3 files, I want wc -l to return 8.

$cat wordlist.txt *[magical union thing]* ls ~/folder/* | wc -l
8

How do I do that?


Solution 1:

Your magical union thing is a semicolon... and curly braces:

    { cat wordlist.txt ; ls ~/folder/* ; } | wc -l

The curly braces are only grouping the commands together, so that the pipe sign | affects the combined output.

You can also use parentheses () around a command group, which would execute the commands in a subshell. This has a subtle set of differences with curly braces, e.g. try the following out:

    cd $HOME/Desktop ; (cd $HOME ; pwd) ; pwd
    cd $HOME/Desktop ; { cd $HOME ; pwd ; } ; pwd

You'll see that all environment variables, including the current working directory, are reset after exiting the parenthesis group, but not after exiting the curly-brace group.

As for the semicolon, alternatives include the && and || signs, which will conditionally execute the second command only if the first is successful or if not, respectively, e.g.

    cd $HOME/project && make
    ls $HOME/project || echo "Directory not found."

Solution 2:

Since wc accepts a file path as input, you can also use process substitution:

wc -l <(cat wordlist.txt; ls ~/folder/*)

This roughly equivalent to:

echo wordlist.txt > temp
ls ~/folder/* >> temp
wc -l temp

Mind that ls ~/folder/* also returns the contents of subdirectories if any (due to glob expansion). If you just want to list the contents of ~/folder, just use ls ~/folder.

Solution 3:

I was asking myself the same question, and ended up writing a short script.

magicalUnionThing (I call it append):

#!/bin/sh
cat /dev/stdin
$*

Make that script executable

chmod +x ./magicalUnionThing

Now you do

cat wordlist.txt |./magicalUnionThing ls ~/folder/* | wc -l

What it does:

  • Send standard input to standard output
  • Execute argument. $* returns all arguments as a string. The output of that command goes to script standard output by default.

So the stdout of magicalUnionThing will be its stdin + stdout of the command that is passed as argument.

There are of course simpler ways, as per other answers.
Maybe this alternative can be useful in some cases.