Gibt es eine Möglichkeit, dies für alle Befehle in bash function / script festzulegen?
Alexander Mills
Antworten:
39
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; }
Dies reduziert die Prozessanzahl tatsächlich nur um eins. (Aber es könnte schneller sein, weil keine regulären Ausdrücke ( sed) oder gar Zeichenfolgenteilung ( awk) verwendet werden.)
Grawity
Übrigens, ich war neugierig auf die Leistung und hier sind die Ergebnisse meines einfachen Benchmarks mit bash, sed und awk. Schieben Sie ungefähr 1000 Textzeilen (dmesg-Ausgabe) in die FIFO-Datei und lesen Sie sie dann so: pastebin.ca/1606844 Sieht aus, als wäre awk der Gewinner. Irgendwelche Ideen warum?
Ilya Zakreuski
1
Seien Sie vorsichtig, wenn Sie solche Timing-Tests durchführen - versuchen Sie, sie in allen 6 verschiedenen Reihenfolgen auszuführen und dann den Durchschnitt der Ergebnisse zu bilden. Unterschiedliche Befehle zum Reduzieren von Blockcache-Effekten und zum Reduzieren von Hintergrundunterbrechungs- / Zeitplanungseffekten.
pjz
Diese Frage hat den Tag "shell" und nicht "bash".
Fiatjaf
1
Einfach genug, um es auch in eine Funktion zu function prepend() { while read line; do echo "${1}${line}"; done; }
Sie können den Bereich der Anführungszeichen einfach verlassen, um die Variable zu dereferenzieren: cmd | awk '{print "['$V]' " $0}'- Dies sollte zu Beginn einmal ausgewertet werden, damit kein Leistungsaufwand entsteht.
Robert
13
Bei aller Dankbarkeit für @grawity sende ich seinen Kommentar als Antwort, da er mir hier die beste Antwort zu sein scheint.
Ich nehme an, es hängt von Ihrem Zweck ab. Wenn Sie einfach jede Zeile in einer Datei voranstellen möchten, können Sie dieses Ziel mit einem sehr vertrauten Werkzeug mit sehr wenigen Zeichen erreichen. Ich ziehe das einem 10-zeiligen Bash-Skript bei weitem vor. Der 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.
Eric Wilson
Die Antwort, die pjz eingereicht hat, ist auch ein netter Einzeiler. Es werden keine zusätzlichen Programme, Prozesse und möglicherweise etwas schneller ausgeführt.
user14645
3
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.
Tino
Nett. Dieser Befehl ist leicht zu verfälschen. 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 .
Im Allgemeinen awkist am schnellsten. sedist etwas langsamer und perlnicht viel langsamer als sed. Anscheinend sind das alles hochoptimierte Sprachen für die Textverarbeitung.
In ganz besonderen Situationen, in denen Gabeln dominieren, kann das Ausführen Ihres Skripts als kompiliertes kshSkript ( shcomp) noch mehr Verarbeitungszeit sparen. Im Gegensatz dazu bashist es im Vergleich zu kompilierten kshSkripten absolut langsam .
Das Erstellen einer statisch verknüpften Binärdatei zu schlagen 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):
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.
Ich habe diesen Ansatz ausprobiert, aber mit diesen >(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
Antworten:
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:
würde es erlauben, verwendet zu werden wie:
quelle
sed
) oder gar Zeichenfolgenteilung (awk
) verwendet werden.)function prepend() { while read line; do echo "${1}${line}"; done; }
Versuche dies:
Prost
quelle
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.
quelle
awk
Einzeiler ist nett genug, aber ich denke, dass mehr Leute damit vertraut sindsed
alsawk
. 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
liestcmd
und führt es nicht aus. Entwedercmd | sed 's/^/[ERROR] /'
odersed 's/^/[ERROR] /' <(cmd)
odercmd > >(sed 's/^/[ERROR] /')
. Aber hüte dich vor Letzterem. Auch wenn Sie auf diese Weise auf den Rückgabewertcmd
dersed
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, dassawk
wahrscheinlich schneller ist alssed
.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. Konntealias
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 undperl
nicht viel langsamer alssed
. Anscheinend sind das alles hochoptimierte Sprachen für die Textverarbeitung.ksh
Skript (shcomp
) noch mehr Verarbeitungszeit sparen. Im Gegensatz dazubash
ist es im Vergleich zu kompiliertenksh
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:
Zwei binäre Varianten eines meiner Tools (es ist jedoch nicht für die Geschwindigkeit optimiert):
Python gepuffert:
Und Python ungepuffert:
quelle
awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'
um einen Zeitstempel auszugebenquelle
sed 's/^/[ERROR] /'
Ich wollte eine Lösung, die stdout und stderr handhabt, also schrieb ich
prepend.sh
und stellte sie in meinen Weg:Jetzt kann ich einfach ausführen
prepend.sh "[ERROR]" cmd ...
, um "[ERROR]" vor die Ausgabe von zu stellencmd
, und habe immer noch stderr und stdout getrennt.quelle
>(
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