GNU/Linux >> Tutoriales Linux >  >> Linux

Un comando para mostrar cada línea hacia adelante y luego hacia atrás

Una función de caparazón. Esto funcionará en cualquier shell que admita <<< here-strings, incluidos zsh y bash.

xyz() { 
    while read line
    do 
        printf "%s " "$line"
        "[email protected]" <<<"$line"
    done
}
$ (echo "foo"; echo "bar") | xyz rev
foo oof
bar rab

Habrá muchos problemas en la mayoría de los casos debido a la forma en que funciona el almacenamiento en búfer de stdio. Una solución para Linux podría ser usar el stdbuf programe y ejecute el comando con coproc, para que pueda controlar explícitamente el intercalado de la salida.

Lo siguiente asume que el comando generará una línea después de cada línea de entrada.

#!/bin/bash
coproc stdbuf -i0 -o0 "[email protected]"
IFS=
while read -r in ; do
    printf "%s " "$in"
    printf "%s\n" "$in" >&${COPROC[1]}
    read -r out <&${COPROC[0]}
    printf "%s\n" "$out"
done

Si se necesita una solución más general, ya que el OP solo requiere cada línea de entrada al programa para eventualmente generar una línea en lugar de inmediatamente, entonces se necesita un enfoque más complicado. Crea un bucle de eventos usando read -t 0 para intentar leer desde stdin y el co-proceso, si tiene el mismo "número de línea" para ambos, luego envíe, de lo contrario almacene la línea. Para evitar usar el 100% de la CPU si en alguna ronda del bucle de eventos ninguno estaba listo, introduzca un pequeño retraso antes de ejecutar el bucle de eventos nuevamente. Hay complicaciones adicionales si el proceso genera líneas parciales, estas deben almacenarse en búfer.

Si se necesita esta solución más general, escribiría esto usando expect ya que ya tiene un buen soporte para manejar la coincidencia de patrones en múltiples flujos de entrada. Sin embargo, esta no es una solución bash/zsh.


En este caso particular, usaría perl :

printf '%s\n' foo bar | perl -Mopen=locale -lpe '$_ .= " " . reverse$_'
foo oof
bar rab

Que podría extender para trabajar también con grupos de grafemas:

$ printf '%s\n' $'complique\u301' |
    perl -Mopen=locale -lpe '$_ .= " " . join "", reverse/\X/g'
compliqué éuqilpmoc

O zsh :

while IFS= read -r line; do
  print -r -- $line ${(j::)${(s::Oa)line}}
done

Aunque evitaría usar while read bucles para procesar texto, incluso en zsh (incluso si en este caso particular, no es tan malo ya que solo se usan los comandos integrados).

En el caso general, usar archivos temporales es probablemente el mejor enfoque. Con zsh , puedes hacerlo con:

(){paste -d ' ' $1 <(rev <$1)} =(print -l foo bar)

(donde =(...) se encarga de crear y limpiar el archivo temporal).

Reemplazándolo con tuberías y alguna forma de tee ing es una receta para el punto muerto en el caso general. Consulte estas preguntas similares para conocer algunos enfoques y detalles sobre las situaciones de interbloqueo:

  • Dividir una entrada para diferentes comandos y combinar el resultado
  • tee + cat:use una salida varias veces y luego concatene los resultados

Linux
  1. ¿Cómo saber en qué versión de Os X estoy desde la línea de comandos?

  2. ¿Procesar cada línea de salida de `ping` inmediatamente en Pipeline?

  3. ¿Cómo analizar cada línea de un archivo de texto como un argumento para un comando?

  4. Agregar salto de línea a la salida del comando

  5. Prefijo para cada salida de un comando en tiempo de ejecución

Lolcat:una herramienta de línea de comandos para generar Rainbow Of Colors en la terminal de Linux

Comando de lectura Bash

Comando Dif en Linux

Prettyping:haga que la salida del comando Ping sea más bonita y fácil de leer

Cómo leer la salida y los usos del comando superior de Linux

¿Cómo leer argumentos de línea de comando en scripts de Shell?