Cómo mostrar y actualizar el eco en la misma línea

112

Tengo lo siguiente en Bash (en Linux)

for dir in Movies/*
do
  (cd "$dir" && pwd|cut -d \/ -f5|tr -s '\n' ', ' >> ../../movielist &&
  exiftool * -t -s3 -ImageSize -FileType|tr -s '\t' ',' >> ../../movielist )
echo "Movie $movies - $dir ADDED!"
let movies=movies+1
done

Pero deseo que el "eco" muestre el siguiente eco en la siguiente línea (no concatenarlo con la última salida de eco, sino reemplazarlo) para que parezca que se está actualizando. Similar a cómo se mostraría una barra de progreso con porcentaje en la misma línea.

Luis Alvarado
fuente

Respuestas:

196

Bueno, no leí correctamente la man echopágina para esto.

echo tenía 2 opciones que podían hacer esto si agregaba un tercer carácter de escape.

Las 2 opciones son -ny -e.

-nno generará la nueva línea final. Así que eso me ahorra ir a una nueva línea cada vez que hago eco de algo.

-e me permitirá interpretar los símbolos de escape de barra invertida.

Supongo que lo que el símbolo de escape que quiero usar para esto: \r. Sí, el retorno de carro me enviaría de regreso al inicio y visualmente parecerá que estoy actualizando en la misma línea.

Entonces la línea de eco se vería así:

echo -ne "Movie $movies - $dir ADDED!"\\r

Tuve que escapar del símbolo de escape para que Bash no lo matara. es por eso que ves 2 \símbolos allí.

Como mencionó William, printftambién puede realizar tareas similares (e incluso más extensas) como esta.

Luis Alvarado
fuente
12
Solo una nota para el futuro: printf hará exactamente lo mismo, sin opciones. La ventaja es que printf generalmente se comporta de manera similar en todos los entornos y sistemas operativos, mientras que echo a veces puede comportarse de manera muy diferente. Para scripts multiplataforma (o si cree que alguna vez le importará), usar printf es la mejor práctica.
William T Froggard
8
printf a; printf bsalidas ab--- printf a\\r; printf bsalidas b--- printf a\\r; sleep 1; printf bsalidas a, luegob
XavierStuvw
64

Si lo he entendido bien, puedes conseguirlo reemplazando tu eco con la siguiente línea:

echo -ne "Movie $movies - $dir ADDED! \033[0K\r"

Aquí hay un pequeño ejemplo que puede ejecutar para comprender su comportamiento:

#!/bin/bash
for pc in $(seq 1 100); do
    echo -ne "$pc%\033[0K\r"
    sleep 1
done
echo
arutaku
fuente
Parece que en zsh Kno es necesario y, de hecho, se
publica
1
Gran ejemplo - para mí el hash bang al principio fue clave
Felix Eve
22

El resto de respuestas son bastante buenas, pero solo quería agregar información adicional en caso de que alguien venga aquí buscando una solución para reemplazar / actualizar un eco multilínea.

Así que me gustaría compartir un ejemplo con todos ustedes. La siguiente secuencia de comandos se probó en un sistema CentOS y usa el comando "timedatectl" que básicamente imprime información detallada de la hora de su sistema.

Decidí usar ese comando ya que su salida contiene varias líneas y funciona perfectamente para el siguiente ejemplo:

#!/bin/bash
while true; do
  COMMAND=$(timedatectl) #Save command result in a var.
  echo "$COMMAND" #Print command result, including new lines.

  sleep 3 #Keep above's output on screen during 3 seconds before clearing it

  #Following code clears previously printed lines
  LINES=$(echo "$COMMAND" | wc -l) #Calculate number of lines for the output previously printed
  for (( i=1; i <= $(($LINES)); i++ ));do #For each line printed as a result of "timedatectl"
    tput cuu1 #Move cursor up by one line
    tput el #Clear the line
  done

done

Lo anterior imprimirá el resultado de " timedatectl" para siempre y reemplazará el eco anterior con resultados actualizados.

Debo mencionar que este código es solo un ejemplo, pero tal vez no sea la mejor solución para ti dependiendo de tus necesidades. Un comando similar que haría casi lo mismo (al menos visualmente) es " watch -n 3 timedatectl".

Pero esa es una historia diferente. :)

¡Espero que ayude!

Antony Fuentes Artavia
fuente
3

Esto es muy útil. Pruébelo y cámbielo según sea necesario.

#! bin/bash
for load in $(seq 1 100); do
    echo -ne "$load % downloded ...\r"
    sleep 1
done
echo "100"
echo "Loaded ..."
Mantu
fuente
3

Puedes probar esto ... Mi propia versión ...

funcc() {
while true ; do 
for i in \| \/ \- \\ \| \/ \- \\; do 
  echo -n -e "\r$1  $i  "
sleep 0.5
done  
#echo -e "\r                                                                                      "
[ -f /tmp/print-stat ] && break 2
done
}

funcc "Checking Kubectl" & &>/dev/null
sleep 5
touch /tmp/print-stat
echo -e "\rPrint Success                  "
Raghu K
fuente
1

Mi forma favorita se llama do the sleep to 50. Aquí la ivariable debe usarse dentro de las declaraciones de eco.

for i in $(seq 1 50); do
  echo -ne "$i%\033[0K\r"
  sleep 50
done
echo "ended"
Stphane
fuente
esto es bueno, pero el cursor oculta el primer carácter. Supongo que algunos espacios en el eco podrían evitar eso.
maratón