Ich habe eine Textdatei, die in jeder Zeile einen Dateinamen enthält:
111_c4l5r120.png
123_c4l4r60.png
135_c4l4r180.png
147_c4l3r60.png
15_c4l1r120.png
...
Ich möchte es in diese Form umwandeln:
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
...
mit diesem Code:
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "$line" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"
aber das Ergebnis ist:
111_c4l5r120.png
111
123_c4l4r60.png
123
135_c4l4r180.png
135
147_c4l3r60.png
147
15_c4l1r120.png
15
...
Wie muss ich mein Skript ändern, um die gewünschte Ausgabe zu erhalten?
Antwort1
Machen Sie so etwas nicht in der Shell! Es ist viel komplexer als nötig, fehleranfällig und viel, viel langsamer. Es gibt viele Tools, die für solche Textmanipulationen entwickelt wurden. Zum Beispiel in sed
(hier unter der Annahme aktueller GNU- oder BSD-Implementierungen für -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
Oder für alle 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
Antwort2
Sofern Sie hierfür nicht unbedingt die Shell verwenden müssen,Terdons Antwortbietet bessere Alternativen.
bash
Da Sie (wie im Shebang des Skripts angegeben) verwenden , können Sie die -n
Option zum Echo verwenden:
echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt
Oder Sie können Shell-Funktionen verwenden, um die Zeile ohne Folgendes zu verarbeiten cut
:
echo "${line} ${line%%_*}" >> output.txt
(beide echo
Zeilen ersetzen).
Alternativ printf
würde es auch funktionieren, funktioniert in jedemPOSIX-Shellund ist im Allgemeinen besser (sieheWarum ist printf besser als echo?für Details):
printf "%s " "${line}" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt
oder
printf "%s %s\n" "${line}" "${line%%_*}" >> output.txt
(Genau genommen, im Klartext /bin/sh
,echo -n
ist nicht tragbar. Da Sie bash
es explizit verwenden, ist es hier in Ordnung.)
Antwort3
Hier sind Sie ja:
#!/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"
Ausgabe:
$ 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