ChrisW
ChrisW

Reputation: 1295

Collecting commands at the same place in pipe

how can one have multiple commands (collected together) at the same position in a pipe? i.e. what comes before in the pipe gets fed into each of those commands separately and sequentially, and their combined output gets fed into the next step of the pipe. For example, how could I make some variation of this pipe

echo -e "1\n2\n3" | { head -1; tail -1; } | xargs echo

print 1 3, instead of just 1?

Thanks

Upvotes: 1

Views: 55

Answers (1)

hek2mgl
hek2mgl

Reputation: 158050

what comes before in the pipe gets fed into each of those commands separately and sequentially, and their combined output gets fed into the next step of the pipe

This is not possible since of the nature of a pipe. Once data is read from a pipe it gets removed from the pipe. That's why there can be only one reader.

I would copy the output of the first command into a temporary file and than feed it to both commands head and tail. If you launch head and tail in a subshell you can feed their combined output to another command:

Btw, a code block between curly brackets does not launch a subshell. You need to use parentheses. The following command seems the closest to what you want:

echo -e "1\n2\n3" > file.tmp ; ( head -1 file.tmp ; tail -qn1 file.tmp; rm file.tmp ) | next_command

About the special use case: Printing the first and the last line from a file

I would use sed for that purpose:

sed -n '1p;$p'

This will print the first and the last line of a file. However it works only for files which contain at least two lines. If the file contains a single line it would get printed twice. You can get around this restriction using the following command:

sed -n 'x;s/^/1/;x;1p;${x;/11/{x;p}}'

The command above adds a 1 to the hold buffer on every line. At the end of the script (which could be after the first line) it checks if there are at least two 1 in the hold buffer and prints the last line if this is true.

Upvotes: 3

Related Questions