Bash/pv Salida “^M” al final de cada línea

7 minutos de lectura

Avatar de usuario de Kevitto
Kevitto

Súper simple, pero NO TENGO IDEA de cómo arreglar esto. Tengo una línea pv súper simple (o eso pensé) que escribe en un archivo, pero la salida agrega “^M” al final de cada línea que el comando tail no interpreta correctamente.

Para explicarlo, estoy escribiendo una imagen en un módulo de cómputo (CM3 o CM4) con pv y enviando el stderr a un archivo temporal que puedo leer desde un cuadro de diálogo más abajo en el código.

Por alguna razón, el tailboxbg que estoy usando no se da cuenta de que está cambiando y solo mantiene la primera línea publicada (ya que se adjunta con “^M”, que no es una nueva línea), pero nunca especifico en ningún lugar para agregar eso al final de la línea.

El código:

pv -teabf -s "$copySize" "$copyImage" > "devCompMod" 2> _temp &

El archivo _temp:

 429MiB 0:00:01 [ 429MiB/s] ETA 0:00:33^M 819MiB 0:00:02 [ 408MiB/s] ETA 0:00:34^M 880MiB 0:00:03 [ 292MiB/s] ETA 0:00:47^M 939MiB 0:00:04 [ 234MiB/s] ETA 0:00:59^M 999MiB 0:00:05 [ 199MiB/s] ETA 0:01:09^M 1.34GiB 0:00:06 [ 229MiB/s] ETA 0:00:59^M
pv: write failed: No space left on device

Cualquier ayuda sería muy apreciada, estoy perdiendo la cabeza aquí.

Probé diferentes redirecciones, pero no tengo idea de cómo canalizar stderr a través de otra cosa sin arruinar por completo mi lectura de archivos, ya que se ejecuta en una subcapa (“&”).

EDITAR: Una combinación de dos sugerencias sobre la respuesta aceptada terminó funcionando para mí. Es mi culpa, no agregué suficiente código circundante, era demasiado preciso.

De todos modos, para cualquiera que necesite esto en el futuro, terminé usando:

pv -F $'%b %t %a %e\n' -f -s "$cpSize" "$cpImage" > "$devTofu" 2> _temp &

Y leyendo las líneas directamente de _temp (En lugar de usar _pvoutput) mediante el uso:

lastLines="$(tail -n 2 _temp | tr -d $'\r\n')"

terminé usando -n 2 porque a tail le costaba llegar a la última línea ya que siempre comenzaba con un ^M y terminó con un \n.

¡Gracias por toda tu ayuda!

  • ^M es \r. Usos de Unix \n para finales de línea, uso de MSDOS y Windows \r\n. Usa una herramienta como dos2unix o una búsqueda global y reemplazo para deshacerse del extra ^M. Luego configure VS Code para no agregarlos.

    – Roberto

    16 de febrero a las 15:33

  • Parece que el final de la línea es justo a \rque es un final de línea clásico de Mac

    – cmbuckley

    16 de febrero a las 15:37

  • También lo leí, pero en ninguna parte de la cadena uso MSDOS o Windows (codifico en OSX y mi entorno de producción está en Debian). Además, es la fotovoltaica la que está generando la ^Ms al archivo. Solo lo escribe PV y se elimina después de su uso.

    – Kevitto

    16 de febrero a las 15:39

  • Estoy bastante seguro pv usa el retorno de carro en su salida de estado porque está destinado a ir a una terminal, y hacer que cada actualización sobrescriba la anterior en la misma línea en lugar de ir a una nueva línea.

    – Gordon Davison

    16 de febrero a las 17:32

  • Entonces, en resumen, ¿por qué diablos estás usando pv en absoluto si está escribiendo la salida en un archivo?

    – triplete

    17 de febrero a las 8:45

Esto no tiene nada que ver con dos o mac. Es solo que realmente tiene la intención de agregar un \r tener una línea de estado actualizándose, en lugar de repetirlos muchas veces. Lo hago a menudo en mi propio código.

Una solución podría ser agregar otro comando para reemplazar \r por \n.

pv -teabf -s "$copySize" "$copyImage" 2>&1 > "devCompMod" | tr $'\r' $'\n'

Por cierto, así es como canalizas stderr. Simplemente rediríjalo a stdout. Pero asegúrese, por supuesto, de redirigir stdout a otra cosa. Cosa que ya hiciste.

Lo que parece antinatural para la mayoría de las personas con esto es el orden. El instinto podría decir que debería cmd > stdout.txt 2>&1 | stderrfilter. Es decir, primero tome el contenido original de stdout a un archivo, y ahora que este contenido ha sido “desplazado”, use el stdout ahora vacío para contener stderr con 2>&1y luego canalizarlo.

Pero eso no es lo que significan las redirecciones. No es el contenido lo que desplazas. Son descriptores de archivos. a>&bes la versión bash de dup2(b,a)

Así que véalo más como una especie de variables que contienen el destino de las salidas. cuyos valores iniciales son dest1 = STDOUT, dest2 = STDERR. Todo lo que se imprime en stdout va a dest1. Todo lo que se imprime en stderr va a dest2. A menos que redirija algo. > outfile.txtcambios dest1 = outfile.txt. 2>&1 cambios dest2 a lo que sea que esté en dest1como dest2 = dest1.

Entonces, haciendo cmd > stdout.txt 2>&1 | filteres como dest1=stdout.txt ; dest2=dest1. Así que ese orden no funciona. Significa que todas las salidas van (mezcladas) a stdout.txt.

En cambio cmd 2>&1 > stdout.txt | filteres como dest2=dest1; dest1=stdout.txt así que primero cambia dest2 al valor inicial de dest1eso es STDOUT entonces dest1 a stdout.txt. Así que la salida estándar de cmd va a stdout.txty su salida err va a STDOUT, es decir, a la tubería.

Por supuesto, eso no es realmente cómo funciona. Pero eso es esquemáticamente cómo entender en qué orden usar las tuberías y redirecciones. Una vez más, piense en ellos como variables que contienen destinos. Que tienes que asignar en un orden lógico. Y no como contenido, que hay que desplazar.

Y de todos modos, el orden correcto para redirigir la salida estándar a un archivo y el error estándar a una tubería es pv ... 2>&1 > outfile | filter

De otra manera

Si no quiere tener problemas con la redirección, otra forma podría ser decir pv para agregar un \n mismo, creando la cadena de salida con la opción de formato.

pv -F $'%t %e %a %b\n' -f -s "$copySize" "$copyImage" > "devCompMod" 

Pero eso no es ideal. En primer lugar, no elimina la \r (en una terminal, la única consecuencia es que el cursor está al principio de la línea, no al final. Supongo que a la mayoría de las líneas de análisis de herramientas tampoco les importaría. Pero nunca se sabe). Solo agrega un \n.

Y en segundo lugar, supongo que en realidad le gustaría redirigir el resultado de todos modos, ya que supongo que su objetivo es alimentar otra herramienta con la indicación de progreso, que es stderr de pv. Su _temp probablemente fue una solución porque no podía redirigir stderr en una tubería… pero ahora que sabe cómo hacerlo, supongo que no usaría eso _temp ya no.

Pero, bueno, si te funciona, probablemente sea preferible a agregar otro comando en tu cadena de tuberías (además, no sé si tr no agrega una latencia)

Entonces, tl; dr

pv -F $'%t %e %a %b\n' -f -s "$copySize" "$copyImage" > "devCompMod" 2> _temp

o

pv -teabf -s "$copySize" "$copyImage" 2>&1 > "devCompMod" | tr $'\r' $'\n' > _temp

si quieres el progreso en _temp. Preferiblemente el primero; el 2 si el \r que todavía están (además de agregados \n) en la primera salida son un problema.

Y si desea redirigir esa salida a un comando de diálogo, en lugar de usar un archivo temporal.

pv -F $'%t %e %a %b\n' -f -s "$copySize" "$copyImage" 2>&1 > "devCompMod" | dialog

o

pv -teabf -s "$copySize" "$copyImage" 2>&1 > "devCompMod" | tr $'\r' $'\n' | dialog

  • Ho-ly, gracias por la explicación! Probaré esto y volveré con una actualización de estado. Encontré una forma alternativa de hacerlo, pero es mucho peor que esto, así que lo intentaré una vez que llegue a mi máquina de producción. Editar: estoy usando el archivo _temp porque ese comando se ejecuta en una subcapa, y el cuadro de diálogo que lo usa como indicador tiene su propio ciclo while que escucha el subproceso, desinfecta los datos, calcula el porcentaje restante y lo canaliza en el opción de diálogo.

    – Kevitto

    17 de febrero a las 15:19


¿Ha sido útil esta solución?