¿Cómo eliminar \ n entre las salidas de dos comandos de eco?

13

Tengo un archivo de texto que contiene un nombre de archivo en cada línea:

111_c4l5r120.png
123_c4l4r60.png
135_c4l4r180.png
147_c4l3r60.png
15_c4l1r120.png
...

Quiero convertirlo de esta forma:

111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
...

usando este código:

#!/bin/bash
while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" >> output.txt   
   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

pero el resultado es:

111_c4l5r120.png 
111
123_c4l4r60.png 
123
135_c4l4r180.png 
135
147_c4l3r60.png 
147
15_c4l1r120.png 
15
...

¿Cómo debo cambiar mi script para tener el resultado deseado?

Ali
fuente
Google encuentra mejores resultados, por ejemplo, esto .
Thomas Dickey

Respuestas:

17

A menos que tenga una necesidad específica de usar el shell para esto, la respuesta de terdon proporciona mejores alternativas.

Como está usando bash(como se indica en el shebang del script), puede usar la -nopción para hacer eco:

echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

O puede usar las funciones de shell para procesar la línea sin usar cut:

echo "${line} ${line%%_*}" >> output.txt

(reemplazando ambas echolíneas).

Alternativamente, printftambién funcionaría, funciona en cualquier shell POSIX y generalmente es mejor (vea ¿Por qué es printf mejor que echo? Para más detalles):

printf "%s " "${line}" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

o

printf "%s %s\n" "${line}" "${line%%_*}" >> output.txt

(Estrictamente hablando, en términos simples /bin/sh, echo -nno es portátil . Ya que está usando explícitamente bash, está bien aquí).

Stephen Kitt
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
terdon
23

¡No hagas este tipo de cosas en la cáscara! Es mucho más complejo de lo necesario, propenso a errores y mucho, mucho más lento. Hay muchas herramientas diseñadas para tal manipulación de texto. Por ejemplo, en sed(aquí suponiendo implementaciones recientes de GNU o BSD para -E):

$ sed -E 's/([^_]*).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

O, para cualquier sed:

$ sed 's/\([^_]*\).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

Perl:

$ perl -pe 's/(.+?)_.*/$& $1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

awk:

$ awk -F_ '{print $0,$1}' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
terdon
fuente
1
Sin embargo, las utilidades externas no son mucho mejores.
EKons
66
@ ΈρικΚωνσταντόπουλος sí, lo son. Varios órdenes de magnitud más rápido, en realidad. El caparazón no es muy bueno en este tipo de cosas. El trabajo principal de un shell es lanzar utilidades externas, después de todo. Compare el tiempo que lleva el enfoque del OP con el que toma cualquiera de las soluciones aquí. Los bucles de concha son muy, muy lentos. Si necesitas más convincente, lee esto .
terdon
En términos de portabilidad, no. En términos de velocidad, sí. Además, ¿@ StéphaneChazelas es tu alias?
EKons
44
@ ΈρικΚωνσταντόπουλος Θα 'θελα :) No, simplemente ha escrito 2 excelentes respuestas que fueron relevantes para los dos hilos de comentarios. En cuanto a la portabilidad, con la excepción (menor) del enfoque perl que solo funcionará en algo así como ~ 90% de las máquinas * nix, las tres soluciones son portátiles y agnósticas. O bien, siempre puedes convertirlo seden uno sed 's/\([^_]*\).*/& \1/' filepara una portabilidad adicional. El punto es que puedes contar awky sedestar allí más de lo que puedes contar con casi cualquier otra cosa.
terdon
2

Aquí estás:

#!/bin/bash

while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" `echo "$line" | cut -d'_' -f 1` >> output.txt
#   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

Salida:

$ rm -rf output.txt
$ ./test.sh 1.1; cat output.txt
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
Putnik
fuente