Frage Befehl, um jeder Zeile eine Zeichenfolge voranzustellen?


Auf der Suche nach so etwas? Irgendwelche Ideen?

cmd | prepend "[ERRORS] "

[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc

24
2017-10-08 23:17


Ursprung


Gibt es eine Möglichkeit, dies für alle Befehle in bash function / script einzurichten? - Alexander Mills


Antworten:


cmd | while read line; do echo "[ERROR] $line"; done

hat den Vorteil, nur Bash-Builtins zu verwenden, so dass weniger Prozesse erstellt / zerstört werden sollte Sei schneller als awk oder sed.


34
2017-10-09 05:23



Dies reduziert die Prozessanzahl tatsächlich nur um eins. (Aber es könnte schneller sein, weil keine Regexps (sed) oder sogar String Splitting (awk) werden verwendet.) - grawity
Übrigens war ich neugierig auf die Leistung und hier sind die Ergebnisse meiner einfachen Benchmark mit bash, sed und awk. Etwa 1000 Zeilen Text (dmesg-Ausgabe) in die FIFO-Datei schieben und dann so lesen: pastebin.ca/1606844 Sieht aus wie awk ist der Gewinner. Irgendwelche Ideen warum? - Ilya Zakreuski
seien Sie vorsichtig bei der Durchführung von Timing-Tests - versuchen Sie, sie in allen 6 verschiedenen Reihenfolgen auszuführen und dann die Ergebnisse zu mitteln. Verschiedene Befehle, um Block-Cache-Effekte und den Durchschnitt zu verringern, um Hintergrundunterbrechungs- / Planungseffekte zu verringern. - pjz
Diese Frage ist mit "shell", nicht mit "bash" markiert. - fiatjaf
Einfach genug, um es in eine Funktion zu verpacken: function prepend() { while read line; do echo "${1}${line}"; done; } - tzrlk


Versuche dies:

cmd | awk '{print "[ERROR] " $0}'

Prost


35
2017-10-08 23:32



Dies hat den Nachteil, dass "[ERROR]" keine Variable sein kann, weil der ganze Ausdruck in einfachen Anführungszeichen stehen muss. - user1071136
awk -vT="[ERROR] " '{ print T $0 }' oder awk -vT="[ERROR]" '{ print T " " $0 }' - Tino
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }' oder T="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }' - Tino
Sie können den Gültigkeitsbereich der Anführungszeichen einfach verlassen, um die Variable zu dereferenzieren: cmd | awk '{print "['$V]' " $0}' - Dies sollte einmal am Start ausgewertet werden, also kein Leistungsaufwand. - robert


Mit allem Respekt für @grawity, ich gebe seinen Kommentar als Antwort, wie es scheint die beste Antwort hier für mich.

sed 's/^/[ERROR] /' cmd

10
2018-01-31 17:38



Warum ist das der bash-Lösung vorzuziehen? - user14645
Ich nehme an, es hängt von deinem Zweck ab. Wenn Ihr Ziel ist, einfach jeder Zeile in einer Datei voranzukommen, erreicht dies dieses Ziel mit sehr wenigen Zeichen, wobei ein sehr vertrautes Werkzeug verwendet wird. Ich ziehe das einem 10-Zeilen-Bash-Skript vor. Das awkOne-Liner 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. - Eric Wilson
Die Antwort, die pjz einreichte, ist auch ein schöner One-Liner. Es gibt keine zusätzlichen Programme, Prozesse und kann Lauf ein bisschen schneller. - user14645
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 das erlaubt Ihnen den Zugriff auf den Rückgabewert von cmd das sed läuft im Hintergrund, so ist es wahrscheinlich, dass Sie die Ausgabe sehen nach dem cmd fertig. Gut für die Anmeldung in einer Datei. Und beachte das awk ist wahrscheinlich schneller als sed. - Tino
Nett.  Dieser Befehl wird leicht mit einem Alias ​​versehen. alias lpad="sed 's/^/ /'". anstelle von ERROR füge ich 4 führende Leerzeichen ein. Nun, für den Zaubertrick: ls | lpad | pbcopy wird ls mit 4 Leerzeichen vorangestellt, was es als markiert Abschlag zum Code, was bedeutet, dass Sie die Zwischenablage einfügen (pbkopie packt es, auf Macs) direkt in StackOverflow oder irgendeinen anderen Markdown-Kontext. Könnte nicht alias das awk Antwort (beim ersten Versuch), also gewinnt dieser. Das während gelesen Lösung ist auch Alias-fähig, aber ich finde das sed ausdrucksvoller. - JL Peyret


Ich habe ein GitHub-Repository um einige Geschwindigkeitstests durchzuführen.

Das Ergebnis ist:

  • Im allgemeinen Fall awk ist am schnellsten. sed ist ein bisschen langsamer und perl ist nicht viel langsamer als sed. Offenbar sind all diese hochoptimierten Sprachen für die Textverarbeitung.
  • In ganz besonderen Situationen, in denen die Gabeln dominieren, läuft dein Skript als kompiliert ksh Skript (shcomp) kann noch mehr Verarbeitungszeit sparen. Im Gegensatz, bash ist tot langsam im Vergleich zu kompiliert ksh Skripte.
  • Erstellen einer statisch verknüpften Binärdatei zum Beaten awk scheint die Mühe nicht wert zu sein.

Im Gegensatz python ist tot langsam, aber ich habe einen kompilierten Fall nicht getestet, weil 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 Werkzeuge (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,'

6
2018-02-22 04:31



awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }' um einen Zeitstempel auszugeben - Tino


cmd | sed 's/.*/[ERROR] &/'

4
2017-10-09 00:12



sed 's/^/[ERROR] /' - grawity


Ich wollte eine Lösung, die stdout und stderr behandelt, also schrieb ich prepend.sh und leg es mir in den 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 rennen prepend.sh "[ERROR]" cmd ..., um "[ERROR]" dem Ausgang von cmdund haben immer noch stderr und stdout getrennt.


2
2017-09-02 09:39



Ich habe diesen Ansatz versucht, aber da war etwas los >( Subhells, die ich nicht ganz auflösen konnte. Es schien, als würde das Skript abgeschlossen, und die Ausgabe erreichte das Terminal nach dem Die Aufforderung war zurückgekehrt, was ein wenig unordentlich war. Ich kam schließlich auf die Antwort hier stackoverflow.com/a/25948606/409638 - robert