¿Hay alguna forma de leer líneas desde la salida del comando?

8

Tengo un comando de preproceso para generar un archivo

./preprocess.sh > preprocessed_file 

y preprocessed_filese usará así

while read line
do

    ./research.sh $line &

done < preprocessed_file 

rm -f preprocessed_file

¿Hay alguna forma de dirigir la salida a la while read lineparte en lugar de enviarla al archivo preprocesado? Creo que debería haber una mejor manera que no sea usar esta temperatura preprocessed_file.

Marcus Thornton
fuente

Respuestas:

8

Puede usar la sustitución del proceso bash :

while IFS= read -r line; do
  ./research.sh "$line" &
done < <(./preprocess.sh)

Algunas ventajas de la sustitución de procesos:

  • No es necesario guardar archivos temporales.
  • Mejor interpretación. Leer desde otro proceso a menudo más rápido que escribir en el disco, luego volver a leer.
  • Ahorre tiempo en el cálculo ya que cuando se realiza simultáneamente con la expansión de parámetros y variables, sustitución de comandos y expansión aritmética
Cuonglm
fuente
¿Qué significan las flechas dobles a la izquierda (<<)?
Marcus Thornton
@MarcusThornton: <es una redirección, mientras que <(...)es la sintaxis de sustitución del proceso. Debería leer: gnu.org/software/bash/manual/html_node/… para más detalles.
Cuonglm
Entendido. <(...)es parte de la sintaxis.
Marcus Thornton el
2
No es necesariamente más rápido. Porque cuando se lee desde una tubería readtiene que leer un byte a la vez, mientras que puede optimizar las cosas con la lectura de fragmentos más grandes y buscar hacia atrás cuando se lee desde un archivo normal. Lo mejor es evitar los while readbucles por completo en primer lugar cuando sea posible. También tenga en cuenta que necesita IFS= read -r lineleer la línea $line. Y dejar sin $linecomillas (invocando al operador split + glob) aquí probablemente no tiene sentido.
Stéphane Chazelas
1
@mikeserv, los comandos a menudo line-buffer (en oposición a full-buffer) su salida cuando va a una terminal. Aquí estoy diciendo que el readshell incorporado lee un carácter a la vez cuando lee desde una tubería (independientemente de lo que hay en el otro extremo de la tubería que readno tiene forma de saber), que es una de las razones por las que los while readbucles son tremendamente lentos.
Stéphane Chazelas
15

¡Si! Puede usar una tubería de proceso |.

./preprocess.sh |
    while IFS= read -r line
    do
        ./research.sh "$line" &
    done

Una tubería de proceso pasa la salida estándar ( stdout) de un proceso a la entrada estándar ( stdin) del siguiente.

Opcionalmente, puede poner un carácter de nueva línea después de a |y extender el comando a la siguiente línea.

Nota: a|bes equivalente a b < <(a), pero sin los archivos mágicos, y en un orden más legible, especialmente cuando la tubería se hace más larga.

a|b|c es equivalente a c < <(b < <(a))

y

a|b|c|d|e es e < < (d < <(c < <(b < <(a))))

ctrl-alt-delor
fuente
3
Nota: Esta solución con la tubería tiene la ventaja de ser más portátil que la sustitución de procesos (no es compatible con algunos shells POSIX como el tablero). Aún con respecto a la portabilidad, el lado derecho de una tubería puede ejecutarse en un subshell (esto depende del shell), de modo que cualquier efecto secundario (como el establecimiento de variables) puede no afectar el entorno del script del shell.
vinc17
Generalmente es más seguro poner referencias variables como $linecomillas dobles (por ejemplo, en su secuencia de comandos ./research.sh "$line" &).
G-Man dice 'Restablecer a Monica' el
1
@ G-Man Posiblemente no en este contexto. Si research.shfunciona con la matriz de argumentos de la línea de comandos y $linees, por ejemplo, "uno dos", con la intención de que el primer argumento sea "uno" y el segundo argumento "dos", las citas $linelo harán imposible; en cambio, el primer argumento será "uno dos" y no habrá un segundo ...
goldilocks
2
" a|bes equivalente ab < <(a) " - cerca, pero no del todo. En la versión de tubería, ambos lados de la tubería se ejecutan en subcapas, mientras que en la versión de sustitución de proceso, solo el proceso sustituido se ejecuta en una subcapa, pero ase ejecuta en el ámbito del nivel de shell que se está ejecutando actualmente. Esto tiene implicaciones importantes para el alcance de las variables establecidas ena
Digital Trauma