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 en 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 obtener el resultado deseado?
Respuesta1
¡No hagas este tipo de cosas en el caparazón! Es mucho más complejo de lo necesario, propenso a errores y mucho, mucho, más lento. Existen muchas herramientas diseñadas para este tipo de manipulación de texto. Por ejemplo, en sed
(aquí asumiendo 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 cualquiera 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
Perla:
$ 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
mal:
$ 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
Respuesta2
A menos que tenga una necesidad específica de utilizar el shell para esto,la respuesta de terdónofrece mejores alternativas.
Ya que estás usando bash
(como se indica en el shebang del script), puedes usar la -n
opción para hacer eco:
echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt
O puede usar funciones de Shell para procesar la línea sin usar cut
:
echo "${line} ${line%%_*}" >> output.txt
(reemplazando ambas echo
líneas).
Alternativamente, printf
también funcionaría, funciona en cualquiershell POSIX, y generalmente es mejor (ver¿Por qué printf es mejor que echo?para 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 sencillos /bin/sh
,echo -n
no es portatil. Ya que lo estás usando explícitamente, bash
está bien aquí).
Respuesta3
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"
Producción:
$ 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