7

I write a script which sends the input file to CPP, then to grep, then to a certain program:

cpp $1 | grep -v "#" | theprogram

But, "theprogram" requires the input to start with a certain constant line "theprogram-1.0". So, I want to prepend that constant line to the output of grep, just before it is sent to "theprogram".

Of course, I can do all this using a temporary file... but I am sure there is a way to do such a simple task in a single line of shell pipes, without temporary files. What is the trick?

2 Answers 2

8

You can surround a sequence of commands with parentheses. Each command inside the parentheses will have access to the same stdin, stdout, and stderr. Here, echo will send to stdout but will not alter the stdin that grep sees.

cpp $1 | (echo 'your constant line here'; grep -v "#") | theprogram

As described in Shell command language: grouping commands, one can use braces instead of parentheses for grouping. Using braces is slightly more efficient, since a subshell won't be created, but it presents more complicated syntax: there needs to be a field separator after the {, and a delimiter such as ; or newline before the }. But several people have suggested it as an alternative, so here it is:

cpp $1 | { echo 'your constant line here'; grep -v "#"; } | theprogram
3
  • You don't need a subshell here, just use a command group.
    – Chris Down
    Commented Jan 20, 2014 at 6:36
  • 1
    @ChrisDown, in practice, that won't make a difference whatsoever, the shell still needs to create a subshell either way. Commented Jun 9, 2023 at 18:40
  • 1
    Actually, with bash specifically (here with version 5.2), strace -c shows the version with braces being less efficient as it forks one extra process and in my test did an additional 19 system calls in total compared to the version with (...) Commented Jun 9, 2023 at 18:51
0

You can use awk thusly:

cpp $1 | grep -v "#" | awk 'BEGIN{print "your line here"}{print}' | theprogram

The BEGIN block is executed once at the beginning, then the primary block prints every line it sees as input.

1
  • Or cpp $1 | awk 'BEGIN{print "your line here"}; ! /#/' | theprogram here. Commented Jun 9, 2023 at 18:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .