Buscando algo como esto? ¿Algunas ideas?
cmd | prepend "[ERRORS] "
[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc
Buscando algo como esto? ¿Algunas ideas?
cmd | prepend "[ERRORS] "
[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc
Respuestas:
cmd | while read line; do echo "[ERROR] $line"; done
tiene la ventaja de usar solo bash builtins, por lo que se crearán / destruirán menos procesos, por lo que debería ser un toque más rápido que awk o sed.
@tzrik señala que también podría ser una buena función bash. Definiéndolo como:
function prepend() { while read line; do echo "${1}${line}"; done; }
permitiría que se use como:
cmd | prepend "[ERROR] "
sed
) o incluso división de cadenas ( awk
).)
function prepend() { while read line; do echo "${1}${line}"; done; }
Prueba esto:
cmd | awk '{print "[ERROR] " $0}'
Aclamaciones
awk -vT="[ERROR] " '{ print T $0 }'
oawk -vT="[ERROR]" '{ print T " " $0 }'
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'
oT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
cmd | awk '{print "['$V]' " $0}'
- esto debe evaluarse una vez al comienzo, para que no haya sobrecarga de rendimiento.
Con todo el crédito debido a @grawity, envío su comentario como respuesta, ya que me parece la mejor respuesta.
sed 's/^/[ERROR] /' cmd
awk
one-liner es lo suficientemente agradable, pero creo que hay más personas con las sed
que está familiarizado awk
. El script bash es bueno para lo que hace, pero parece que está respondiendo una pregunta que no se hizo.
sed X cmd
lee cmd
y no lo ejecuta. O cmd | sed 's/^/[ERROR] /'
o sed 's/^/[ERROR] /' <(cmd)
o cmd > >(sed 's/^/[ERROR] /')
. Pero cuidado con lo último. Incluso eso le permite acceder al valor de retorno de cmd
las sed
ejecuciones en segundo plano, por lo que es probable que vea la salida después de que finalice el cmd. Sin embargo, es bueno para iniciar sesión en un archivo. Y tenga en cuenta que awk
probablemente es más rápido que sed
.
alias lpad="sed 's/^/ /'"
. en lugar de ERROR inserto 4 espacios iniciales. Ahora, para el truco de magia: ls | lpad | pbcopy
antepondrá la salida ls con 4 espacios que lo marcan como Markdown para el código , lo que significa que pega el portapapeles ( pbcopy lo agarra, en Mac) directamente en StackOverflow o cualquier otro contexto de reducción. No se pudo responder alias
el awk (en el primer intento), así que este gana. La lectura, mientras que la solución es también capaz de alias, pero me parece que esta sed más expresiva.
Creé un repositorio de GitHub para hacer algunas pruebas de velocidad.
El resultado es:
awk
es el más rápido. sed
es un poco más lento y perl
no es mucho más lento que sed
. Aparentemente, todos esos son lenguajes altamente optimizados para el procesamiento de texto.ksh
script compilado ( shcomp
) puede ahorrar aún más tiempo de procesamiento. Por el contrario, bash
es muy lento en comparación con los ksh
scripts compilados .awk
no parece valer la pena.Por el contrario, python
es muy lento, pero no he probado un caso compilado, porque generalmente no es lo que haría en un caso de secuencias de comandos.
Se prueban las siguientes variantes:
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] $_"'
Dos variantes binarias de una de mis herramientas (aunque no está optimizada para la velocidad):
./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''
Python tamponado:
python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'
Y Python sin búfer:
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 }'
emitir una marca de tiempo
Quería una solución que manejara stdout y stderr, así que escribí prepend.sh
y la puse en mi camino:
#!/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)
Ahora solo puedo ejecutar prepend.sh "[ERROR]" cmd ...
, para anteponer "[ERROR]" a la salida de cmd
, y todavía tengo stderr y stdout separados.
>(
subcapas que no pude resolver. Parecía que el script se estaba completando, y la salida llegaba a la terminal después de que el aviso había regresado, lo cual era un poco desordenado. Eventualmente se me ocurrió la respuesta aquí stackoverflow.com/a/25948606/409638