Antworten:
cmd | while read line; do echo "[ERROR] $line"; done
hat den Vorteil , nur bash builtins mit so werden weniger Prozesse erstellt / zerstört werden , damit es soll einen Hauch schneller als awk oder sed sein.
@tzrik weist darauf hin, dass es auch eine nette Bash-Funktion machen könnte. Definiere es so:
function prepend() { while read line; do echo "${1}${line}"; done; }
würde es erlauben, verwendet zu werden wie:
cmd | prepend "[ERROR] "
sed
) oder gar Zeichenfolgenteilung ( awk
) verwendet werden.)
function prepend() { while read line; do echo "${1}${line}"; done; }
Versuche dies:
cmd | awk '{print "[ERROR] " $0}'
Prost
awk -vT="[ERROR] " '{ print T $0 }'
oderawk -vT="[ERROR]" '{ print T " " $0 }'
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'
oderT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
cmd | awk '{print "['$V]' " $0}'
- Dies sollte zu Beginn einmal ausgewertet werden, damit kein Leistungsaufwand entsteht.
Bei aller Dankbarkeit für @grawity sende ich seinen Kommentar als Antwort, da er mir hier die beste Antwort zu sein scheint.
sed 's/^/[ERROR] /' cmd
awk
Einzeiler ist nett genug, aber ich denke, dass mehr Leute damit vertraut sind sed
als awk
. Das Bash-Skript ist gut für das, was es tut, aber es scheint, dass es eine Frage beantwortet, die nicht gestellt wurde.
sed X cmd
liest cmd
und führt es nicht aus. Entweder cmd | sed 's/^/[ERROR] /'
oder sed 's/^/[ERROR] /' <(cmd)
oder cmd > >(sed 's/^/[ERROR] /')
. Aber hüte dich vor Letzterem. Auch wenn Sie auf diese Weise auf den Rückgabewert cmd
der sed
Läufe im Hintergrund zugreifen können , wird die Ausgabe wahrscheinlich nach Abschluss von cmd angezeigt. Gut, um sich in eine Datei einzuloggen. Und beachten Sie, dass awk
wahrscheinlich schneller ist als sed
.
alias lpad="sed 's/^/ /'"
. anstelle von ERROR füge ich 4 führende Leerzeichen ein. Nun zum Zaubertrick: ls | lpad | pbcopy
Stellt ls Ausgabe 4 Leerzeichen voran , wodurch es als Markdown für Code gekennzeichnet wird. Dies bedeutet, dass Sie die Zwischenablage ( pbcopy greift danach, auf Macs) direkt in StackOverflow oder einen anderen Markdown-Kontext einfügen. Konnte alias
die awk nicht antworten (beim ersten Versuch), so dass dieser gewinnt. Die während Lese Lösung ist auch Alias-fähig, aber ich finde diesen sed ausdrucksvoller .
Ich habe ein GitHub-Repository erstellt , um einige Geschwindigkeitstests durchzuführen.
Das Ergebnis ist:
awk
ist am schnellsten. sed
ist etwas langsamer und perl
nicht viel langsamer als sed
. Anscheinend sind das alles hochoptimierte Sprachen für die Textverarbeitung.ksh
Skript ( shcomp
) noch mehr Verarbeitungszeit sparen. Im Gegensatz dazu bash
ist es im Vergleich zu kompilierten ksh
Skripten absolut langsam .awk
scheint die Mühe nicht wert zu sein.Im Gegensatz dazu python
ist es absolut langsam, aber ich habe einen kompilierten Fall nicht getestet, da es normalerweise nicht das ist, was Sie in einem solchen Skriptfall tun würden.
Folgende Varianten werden getestet:
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] $_"'
Zwei binäre Varianten eines meiner Tools (es ist jedoch nicht für die Geschwindigkeit optimiert):
./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''
Python gepuffert:
python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'
Und Python ungepuffert:
python -uSc 'import sys
while 1:
line = sys.stdin.readline()
if not line: break
print "[TEST]",line,'
awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'
um einen Zeitstempel auszugeben
Ich wollte eine Lösung, die stdout und stderr handhabt, also schrieb ich prepend.sh
und stellte sie in meinen Weg:
#!/bin/bash
prepend_lines(){
local prepended=$1
while read line; do
echo "$prepended" "$line"
done
}
tag=$1
shift
"$@" > >(prepend_lines "$tag") 2> >(prepend_lines "$tag" 1>&2)
Jetzt kann ich einfach ausführen prepend.sh "[ERROR]" cmd ...
, um "[ERROR]" vor die Ausgabe von zu stellen cmd
, und habe immer noch stderr und stdout getrennt.
>(
Unterschalen war etwas los , das ich nicht ganz lösen konnte. Es schien, als wäre das Skript abgeschlossen und die Ausgabe erreichte das Terminal, nachdem die Eingabeaufforderung zurückgekehrt war, was ein wenig chaotisch war. Ich kam schließlich hier mit der Antwort auf stackoverflow.com/a/25948606/409638