Risposte:
cmd | while read line; do echo "[ERROR] $line"; done
ha il vantaggio di usare solo i built-in bash in modo che vengano creati / distrutti meno processi, quindi dovrebbe essere un tocco più veloce di awk o sed.
@tzrik sottolinea che potrebbe anche fare una bella funzione bash. Definendolo come:
function prepend() { while read line; do echo "${1}${line}"; done; }
gli permetterebbe di essere usato come:
cmd | prepend "[ERROR] "
sed
awk
function prepend() { while read line; do echo "${1}${line}"; done; }
Prova questo:
cmd | awk '{print "[ERROR] " $0}'
Saluti
awk -vT="[ERROR] " '{ print T $0 }'
oppureawk -vT="[ERROR]" '{ print T " " $0 }'
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'
oppureT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
cmd | awk '{print "['$V]' " $0}'
- questo dovrebbe essere valutato una volta all'inizio, quindi nessun sovraccarico di prestazioni.
Con tutto il merito di @grawity, sto inviando il suo commento come risposta, in quanto mi sembra la risposta migliore qui.
sed 's/^/[ERROR] /' cmd
awk
L'one-liner è abbastanza bello, ma penso che più persone hanno familiarità con sed
rispetto awk
. Lo script bash è buono per quello che fa, ma sembra che stia rispondendo a una domanda che non è stata posta.
sed X cmd
legge cmd
e non lo esegue. O cmd | sed 's/^/[ERROR] /'
oppure sed 's/^/[ERROR] /' <(cmd)
oppure cmd > >(sed 's/^/[ERROR] /')
. Ma attenzione a quest'ultimo. Anche che questo ti permette di accedere il valore di ritorno cmd
le sed
corse in background, quindi è probabile che si vede l'uscita dopo cmd finiti. Buono per l'accesso a un file, però. E nota che awk
probabilmente è più veloce di sed
.
alias lpad="sed 's/^/ /'"
. invece di ERRORE inserisco 4 spazi iniziali. Ora, per il trucco magico: ls | lpad | pbcopy
anteporrà l'output con 4 spazi che lo contrassegnano come Markdown per il codice , il che significa che si incolla gli appunti ( pbcopy lo prende, su Mac) direttamente in StackOverflow o in qualsiasi altro contesto markdown. Non è stata alias
la risposta awk (al primo tentativo), quindi questo vince. Anche la soluzione while read è alias, ma trovo questa sed più espressiva.
Ho creato un repository GitHub per eseguire alcuni test di velocità.
Il risultato è:
awk
è il più veloce. sed
è un po 'più lento e perl
non è molto più lento di sed
. Apparentemente, tutti questi sono linguaggi altamente ottimizzati per l'elaborazione del testo.ksh
script compilato ( shcomp
) può risparmiare ancora più tempo di elaborazione. Al contrario, bash
è molto lento rispetto agli ksh
script compilati .awk
non sembra valere la pena.Al contrario python
è molto lento, ma non ho testato un caso compilato, perché di solito non è quello che faresti in un caso di scripting.
Vengono testate le seguenti varianti:
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] $_"'
Due varianti binarie di uno dei miei strumenti (non è ottimizzato per la velocità, però):
./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''
Python bufferato:
python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'
E Python senza buffer:
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 }'
per emettere un timestamp
Volevo una soluzione che gestisse stdout e stderr, quindi l'ho scritta prepend.sh
e inserita nel mio percorso:
#!/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)
Ora posso solo eseguire prepend.sh "[ERROR]" cmd ...
, anteporre "[ERROR]" all'output di cmd
, e avere comunque stderr e stdout separati.
>(
subshells che non riuscivo a risolvere del tutto. Sembrava che lo script fosse completato e l'output stava arrivando al terminale dopo che il prompt era tornato, il che era un po 'disordinato. Alla fine ho trovato la risposta qui stackoverflow.com/a/25948606/409638