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
awkEinzeiler ist nett genug, aber ich denke, dass mehr Leute damit vertraut sind sedals 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 cmdliest cmdund 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 cmdder sedLä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 awkwahrscheinlich schneller ist als sed.
alias lpad="sed 's/^/ /'". anstelle von ERROR füge ich 4 führende Leerzeichen ein. Nun zum Zaubertrick: ls | lpad | pbcopyStellt 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 aliasdie 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:
awkist am schnellsten. sedist etwas langsamer und perlnicht viel langsamer als sed. Anscheinend sind das alles hochoptimierte Sprachen für die Textverarbeitung.kshSkript ( shcomp) noch mehr Verarbeitungszeit sparen. Im Gegensatz dazu bashist es im Vergleich zu kompilierten kshSkripten absolut langsam .awkscheint die Mühe nicht wert zu sein.Im Gegensatz dazu pythonist 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.shund 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