¿Hay alguna manera de configurar esto para todos los comandos en bash function / script?
Alexander Mills
Respuestas:
39
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; }
En realidad, esto solo reduce el recuento de procesos en uno. (Pero podría ser más rápido porque no se utilizan expresiones regulares ( sed) o incluso división de cadenas ( awk).)
Grawity
Por cierto, tenía curiosidad sobre el rendimiento y aquí están los resultados de mi punto de referencia simple usando bash, sed y awk. Empujar alrededor de 1000 líneas de texto (salida dmesg) al archivo FIFO y luego leerlas así: pastebin.ca/1606844 Parece que awk es el ganador. Alguna idea de por qué?
Ilya Zakreuski el
1
tenga cuidado al ejecutar pruebas de tiempo como esa: intente ejecutarlas en los 6 diferentes pedidos y luego promedie los resultados. Diferentes órdenes para mitigar los efectos de caché de bloque y promedio para mitigar la interrupción de fondo / efectos de programación.
pjz
Esta pregunta está etiquetada como "shell", no "bash".
fiatjaf
1
Lo suficientemente fácil como para envolverlo en una función también:function prepend() { while read line; do echo "${1}${line}"; done; }
Simplemente puede salir del alcance de las comillas para desreferenciar la variable: cmd | awk '{print "['$V]' " $0}'- esto debe evaluarse una vez al comienzo, para que no haya sobrecarga de rendimiento.
Robert
13
Con todo el crédito debido a @grawity, envío su comentario como respuesta, ya que me parece la mejor respuesta.
Supongo que depende de tu propósito. Si su objetivo es simplemente anteponer cada línea en un archivo, esto lo logra con muy pocos caracteres, utilizando una herramienta muy familiar. Prefiero eso a un script bash de 10 líneas. El awkone-liner es lo suficientemente agradable, pero creo que hay más personas con las sedque está familiarizado awk. El script bash es bueno para lo que hace, pero parece que está respondiendo una pregunta que no se hizo.
Eric Wilson el
La respuesta que envió pjz también es una buena frase. No tiene programas adicionales, procesos y puede ejecutarse un poco más rápido.
user14645
3
sed X cmdlee cmdy 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 cmdlas sedejecuciones 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 awkprobablemente es más rápido que sed.
Tino
Agradable. Este comando tiene un alias fácil. alias lpad="sed 's/^/ /'". en lugar de ERROR inserto 4 espacios iniciales. Ahora, para el truco de magia: ls | lpad | pbcopyantepondrá 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 aliasel 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.
En el caso general, awkes el más rápido. sedes un poco más lento y perlno es mucho más lento que sed. Aparentemente, todos esos son lenguajes altamente optimizados para el procesamiento de texto.
En situaciones muy especiales, donde dominan los tenedores, ejecutar su script como un kshscript compilado ( shcomp) puede ahorrar aún más tiempo de procesamiento. Por el contrario, bashes muy lento en comparación con los kshscripts compilados .
La creación de un binario estáticamente vinculado para vencer awkno parece valer la pena.
Por el contrario, pythones 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):
Intenté este enfoque, pero sucedía algo con esas >(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
Respuestas:
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:
permitiría que se use como:
fuente
sed
) o incluso división de cadenas (awk
).)function prepend() { while read line; do echo "${1}${line}"; done; }
Prueba esto:
Aclamaciones
fuente
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.
fuente
awk
one-liner es lo suficientemente agradable, pero creo que hay más personas con lassed
que está familiarizadoawk
. El script bash es bueno para lo que hace, pero parece que está respondiendo una pregunta que no se hizo.sed X cmd
leecmd
y no lo ejecuta. Ocmd | sed 's/^/[ERROR] /'
osed 's/^/[ERROR] /' <(cmd)
ocmd > >(sed 's/^/[ERROR] /')
. Pero cuidado con lo último. Incluso eso le permite acceder al valor de retorno decmd
lassed
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 queawk
probablemente es más rápido quesed
.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 responderalias
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 yperl
no es mucho más lento quesed
. 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 losksh
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:
Dos variantes binarias de una de mis herramientas (aunque no está optimizada para la velocidad):
Python tamponado:
Y Python sin búfer:
fuente
awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'
emitir una marca de tiempofuente
sed 's/^/[ERROR] /'
Quería una solución que manejara stdout y stderr, así que escribí
prepend.sh
y la puse en mi camino:Ahora solo puedo ejecutar
prepend.sh "[ERROR]" cmd ...
, para anteponer "[ERROR]" a la salida decmd
, y todavía tengo stderr y stdout separados.fuente
>(
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