Command to prepend string to each line?
Looking for something like this? Any ideas?
cmd | prepend "[ERRORS] "
[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc
cmd | while read line; do echo "[ERROR] $line"; done
has the advantage of only using bash builtins so fewer processes will be created/destroyed so it should be a touch faster than awk or sed.
@tzrik points out that it might also make a nice bash function. Defining it like:
function prepend() { while read line; do echo "${1}${line}"; done; }
would allow it to be used like:
cmd | prepend "[ERROR] "
Try this:
cmd | awk '{print "[ERROR] " $0}'
Cheers
With all due credit to @grawity, I'm submitting his comment as an answer, as it seems the best answer here to me.
sed 's/^/[ERROR] /' cmd
I created a GitHub repository to do some speed tests.
The result is:
- In the general case,
awk
is fastest.sed
is a bit slower andperl
is not much slower thansed
. Apparently, all those are highly optimized languages for text processing. - In very special situations, where forks dominate, running your script as a compiled
ksh
script (shcomp
) can save even more processing time. In contrast,bash
is dead slow compared to compiledksh
scripts. - Creating a statically linked binary to beat
awk
seems not be worth the effort.
In contrast python
is dead slow, but I have not tested a compiled case, because it is usually not what you would do in such a scripting case.
Following variants are tested:
while read line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST]" $line; done
while read -r line; do echo "[TEST]" "$line"; done
sed 's/^/[TEST] /'
awk '{ print "[TEST] " $0 }'
awk -vT="[TEST] " '{ print T $0 }'
awk -vT="[TEST]" '{ print T " " $0 }'
awk -vT="[TEST]" 'BEGIN { T=T " "; } { print T $0 }'
T="[TEST] " awk '{ print ENVIRON["T"] $0 }'
T="[TEST]" awk '{ print ENVIRON["T"] " " $0 }'
T="[TEST]" awk 'BEGIN { T=ENVIRON["T"] " " } { print T $0 }'
perl -ne 'print "[TEST] $_"'
Two binary variants of one of my tools (it is not optimzed for speed, though):
./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''
Python buffered:
python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'
And Python unbuffered:
python -uSc 'import sys
while 1:
line = sys.stdin.readline()
if not line: break
print "[TEST]",line,'
cmd | sed 's/.*/[ERROR] &/'