2010-11-23 9 views
7

Tengo un programa que escribe en fd3 y quiero procesar esos datos con grep y sed. Así es como el código se ve hasta ahora:Cómo detener sed desde el almacenamiento en búfer?


exec 3> >(grep "good:"|sed -u "s/.*:\(.*\)/I got: \1/") 
echo "bad:data1">&3 
echo "good:data2">&3 

Nada se emite hasta que lo haga un

exec 3>&-

Entonces, todo lo que quería por fin llega como yo esperaba:

 
I got: data2 

Parece responder de inmediato si uso solo un grep o solo un sed, pero mezclarlos parece causar algún tipo de almacenamiento en memoria intermedia. ¿Cómo puedo obtener un resultado inmediato de fd3?

Respuesta

3

un medio alternativo para detener sed del búfer es de ejecutarlo a través the s2p sed-to-Perl translator e insertar una directiva para tenerlo comando de búfer, tal vez como

BEGIN { $| = 1 } 

La otra razón para hacer esto es que te la da una notación más conveniente de los ERE en lugar de los BRE legacy de la barra invertida. También obtiene el complemento completo de propiedades Unicode, que a menudo es crítico.

Pero no necesita el traductor para un comando tan simple sed. Y tampoco necesita ambos grep y sed. Todos estos trabajos:

perl -nle 'BEGIN{$|=1} if (/good:/) { s/.*:(.*)/I got: $1/; print }' 

perl -nle 'BEGIN{$|=1} next unless /good:/; s/.*:(.*)/I got: $1/; print' 

perl -nle 'BEGIN{$|=1} next unless /good:/; s/.*:/I got: /; print' 

Ahora también tienen acceso al cuantificador mínimo, *?, +?, ??, {N,}? y {N,M}?. Estos ahora permiten cosas como .*? o \S+? o [\p{Pd}.]??, que bien pueden ser preferibles.

+0

De hecho fui por la ruta Perl como me recomendó. No estaba al tanto de su utilidad en los scripts bash. perl y bash definitivamente van bien juntos. – User1

6

Creo que lo encontré. Por alguna razón, grep no hace automáticamente un buffer de línea. Agregué una opción --line-buffered a grep y ahora responde de inmediato.

+1

'grep' espera ser alimentado con un gran archivo o un gran flujo de tuberías. Totalmente amortiguado es mucho más eficiente en esos casos. (Alégrate de que estés en Linux. Esta computadora OSX en la que estoy escribiendo esto no tiene opciones de buffer de línea para grep o sed). – zwol

+2

Wow. Lo siento mucho por tu máquina OSX. Aún más siento que OSX realmente cuesta dinero. Menos funciones, más dinero, ¿cómo lo logró Apple? – User1

+0

OSX no es realmente * for * hackeo de línea de comandos. Me alegra que mantengan las bases de BSD, pero en esta computadora paso mucho más tiempo en cosas que no son CLI. – zwol

3

Puede combinar la grep en el sed así:

exec 3> >(sed -une '/^good:/s//I got: /p') 
echo "bad:data1">&3 
echo "good:data2">&3 

Desembalaje de que un poco: Usted puede poner una expresión regular (entre barras como de costumbre) antes de cualquier comando sed, lo que hace que sólo se aplicará a líneas que coinciden con esa expresión regular. Si el primer argumento de expresión regular para el comando s es la cadena vacía (s//whatever/), reutilizará la última expresión regular que coincida, que en este caso es el prefijo, por lo que ahorrará tener que repetirse. Y finalmente, la opción -n le dice a sed que imprima solo lo que específicamente se le dice que imprima, y ​​el sufijo /p en el comando s le dice que imprima el resultado de la sustitución.

La opción -e no es estrictamente necesaria, pero es un buen estilo, simplemente significa que "el siguiente argumento es el script sed, no un nombre de archivo".

siempre ponen guiones de sed en comillas simples a menos que necesite sustituir una variable de shell allí, y aún así me gustaría poner todo pero la variable de shell entre comillas simples (la variable de shell es, por supuesto, doble cita) Evita un montón de dolor relacionado con la barra invertida de esa manera.

+0

¡Excelente información - yo * solía * saber todo eso! –

+0

sed, awk, grep, perl ... todos son tan poderosos. Ojalá fuera solo una utilidad porque simplemente no tengo ancho de banda para aprender todos. – User1

+0

La manera correcta de pensarlo es,/bin/sh + todo en "coreutils" es una utilidad que se divide en muchos ejecutables. Awk y perl son sus propias cosas, sin embargo, y honestamente, hoy en día no creo que valga la pena molestarse en aprender awk, porque perl es estrictamente mejor, especialmente si aprendes sus opciones de línea de comando. (Antes tenías que preocuparte por los sistemas que no tenían perl, pero no creo que eso sea relevante nunca más). Además, una habilidad crítica en esta área es saber cuándo abandonar shell y usar perl o python para todo en lugar. – zwol

1

En Mac, brew install coreutils y usa gstdbuf para controlar el almacenamiento en memoria intermedia de grep y sed.

+1

JFTR, es simplemente 'stdbuf' en sistemas GNU/Linux. – kostix

Cuestiones relacionadas