2012-01-05 13 views
5

¿Es posible obtener la salida de un comando, por ejemplo tar, para escribir cada línea de salida en una sola línea?Hacer que la salida del comando aparezca en una sola línea

Ejemplo de uso:

tar -options -f dest source | [insert trickery here] 

y la salida mostraría cada archivo que está siendo procesado sin hacer el movimiento de la pantalla: cada salida sobrescribe el último. Se puede hacer?


Editar: parece que tenemos una respuesta de trabajo, pero permite ir más lejos: ¿Cómo en hacer lo mismo, pero más de 5 líneas? Verá una salida de desplazamiento que no afecta al resto de la terminal. Creo que tengo una respuesta, pero me gustaría ver lo que piensan.

+0

Tiene su edición. Fue divertido. – Dave

Respuesta

6

Reemplace las líneas nuevas con retornos de carro.

tar -options -f dest source | cut -b1-$(tput cols) | sed -u 'i\\o033[2K' | stdbuf -o0 tr '\n' '\r'; echo 

Explicación:

  • cut -b1-$(tput cols): trunca la salida de alquitrán si es más largo que el terminal es amplia. Dependiendo de qué tan poco quieras que se mueva tu terminal, no es estrictamente necesario.

  • sed -u 'i\\o033[2K': inserta una línea en blanco al comienzo de cada línea. La opción -u de sed lo coloca en modo sin búfer. stdbuf -oL sed 'i\\033[2K' funcionaría igual de bien.

  • stdbuf -o0 tr '\n' '\r': utiliza tr para intercambiar nuevas líneas con devoluciones de carro. Stdbuf se asegura de que la salida esté sin búfer; sin el \n, en una línea de terminal con búfer, no veríamos salida.

  • echo: Emite una nueva línea final, de modo que la indicación de la terminal no consuma la última línea.

Para el problema de tu edición propone:

x=0; 
echo -e '\e[s'; 
tar -options -f dest source | while read line; do 
     echo -en "\e[u" 
     if [ $x gt 0 ]; then echo -en "\e["$x"B"; fi; 
     echo -en "\e[2K" 
     echo -n $line | cut -b1-$(tput cols); 
     let "x = ($x+1)%5"; 
done; echo; 

No dude en smush todo eso en una sola línea. En realidad, esto se obtiene una solución alternativa para el problema original:

echo -e '\e[s'; tar -options -f dest source | while read line; do echo -en "\e[u\e2K"; echo -n $line | cut -b1-$(tput cols); done; echo 

que se apoya perfectamente en nada, excepto códigos VT100.

+2

O con retornos de carro, lo que hace que la siguiente línea se sobrescriba: 'tr '\ 012' '\ 015'' – tripleee

+1

Creo que desea imprimir una nueva línea al final para que cuando termine no se estropee. . – mrj

+1

No creo que esto es lo que el OP está buscando en absoluto. Quiere algún tipo de truco de control-personaje (con espacios hacia atrás o algo así) por lo que la salida está escrita en el mismo lugar_. –

3

Gracias a Dave/tripleee para la mecánica principal (en sustitución de los saltos de línea con retornos de carro), aquí está una versión que realmente funciona:

tar [opts] [args] | perl -e '$| = 1; while (<>) { s/\n/\r/; print; } print "\n"' 

Configuración $| causas Perl a ras de forma automática después de cada print, en lugar de esperar nuevas líneas, y la nueva línea final evita que su última línea de salida se sobrescriba (parcialmente) cuando el comando finaliza y bash imprime un mensaje. (Eso es realmente feo si es parcial, con el indicador y el cursor seguidos por el resto de la línea de salida.)

Sería bueno lograr esto con tr, pero no estoy al tanto de cómo forzar tr (o algo similarmente estándar) para vaciar stdout.

Editar: La versión anterior es realmente fea, ya que no borra el resto de la línea después de lo que se ha producido. Eso significa que las líneas más cortas que siguen líneas más largas tienen texto final sobrante. Esta (la verdad fea) establece que:

tar [opts] [args] | perl -e '$| = 1; $f = "%-" . `tput cols` . "s\r"; $f =~ s/\n//; while (<>) {s/\n//; printf $f, $_;} print "\n"' 

(Usted puede también conseguir el ancho de la terminal en más formas de Perl-y, as described here, yo no quiero depender de módulos CPAN aunque

+0

Tampoco me gusta este método. La tubería se ignora por cualquier razón. Además, ¿funcionará Perl para todos? , o tiene que ser instalado primero? – CJxD

+0

No funciona con 'cp' tampoco. 'cp' no se queja, pero tampoco hace lo que debería. Nether hace la respuesta anterior. = [ – CJxD

+0

@CJxD: He probado esto. Funciona absolutamente para mí en Ubuntu. ¿Está posiblemente en una plataforma diferente, donde 'tar' envía su salida a stderr en lugar de stdout? En ese caso, necesitaría agregar '2> & 1' antes de la tubería, para redirigir stderr a stdout para que la tubería lo atrape. – mrj

4
tar -options -f dest source | cut -b1-$(tput cols) | perl -ne 's/^/\e[2K/; s/\n/\r/; print' ;echo 
. Explicaciones:

  • | cut -b1-$(tput cols) Esto es con el fin de asegurarse de que las columnas no son demasiado amplia
  • (en -ne perl) 01.Este código borra la línea actual y borra las líneas "viejas". Esto debe ser al principio de la línea, para garantizar que se conserve la línea final de salida y también para garantizar que no eliminemos una línea hasta que la próxima línea esté disponible.
  • (En perl -ne) s/\n/\r/ El comando tr se puede usar aquí, por supuesto. Pero una vez que empecé a usar Perl, me quedé con él

PS Para aclarar: Hay dos problemas distintos 'line-width'. Ambos deben ser resueltos. (1) Necesitamos borrar las líneas, de modo que una línea corta no se mezcle con líneas más viejas y más largas. (2) Si una línea es muy larga, y es más ancha que el ancho del terminal actual, entonces tenemos que recortarla.

+0

+1 - ¡mucho más limpio que el mío! – mrj

+0

Si estaba al final de la línea, No habría salida; Cada línea que imprime, borrará inmediatamente – Dave

+0

@Dave, he actualizado el funcionamiento un poco. ¿Está bien? Está en el principio para "... garantizar que no eliminemos una línea hasta que la siguiente línea esté disponible". –

Cuestiones relacionadas