Bagaimana cara menghapus \ n antara output dari dua perintah gema?

13

Saya memiliki file teks yang berisi satu nama file di setiap baris:

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

Saya ingin mengubahnya dalam bentuk ini:

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

menggunakan kode ini:

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

tetapi, hasilnya adalah:

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

Bagaimana saya harus mengubah skrip saya untuk mendapatkan hasil keinginan?

Ali
sumber
Google menemukan hasil yang lebih baik, misalnya ini .
Thomas Dickey

Jawaban:

17

Kecuali Anda memiliki kebutuhan khusus untuk menggunakan shell untuk ini, jawaban terdon memberikan alternatif yang lebih baik.

Karena Anda menggunakan bash(seperti yang ditunjukkan dalam shebang skrip), Anda dapat menggunakan -nopsi untuk menggema:

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

Atau Anda dapat menggunakan fitur shell untuk memproses baris tanpa menggunakan cut:

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

(mengganti kedua echobaris).

Atau, printfakan melakukan trik juga, bekerja di shell POSIX , dan umumnya lebih baik (lihat Mengapa printf lebih baik daripada gema? Untuk detail):

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

atau

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

(Sebenarnya, di dataran /bin/sh, echo -ntidak portabel . Karena Anda secara eksplisit menggunakannya bashtidak masalah di sini.)

Stephen Kitt
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
terdon
23

Jangan lakukan hal semacam ini di shell! Itu jauh lebih kompleks dari yang diperlukan, rawan kesalahan dan jauh, jauh, lebih lambat. Ada banyak alat yang dirancang untuk manipulasi teks seperti itu. Misalnya, dalam sed( di sini mengasumsikan implementasi GNU atau BSD terbaru untuk -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

Atau, untuk apa saja 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
sumber
1
Utilitas eksternal tidak jauh lebih baik.
EKons
6
@ ΈρικΚωνσταντόπουλος ya mereka. Beberapa urutan besarnya lebih cepat, sebenarnya. Shell tidak begitu bagus dalam hal semacam ini. Pekerjaan utama shell adalah meluncurkan utilitas eksternal. Bandingkan waktu yang diambil dengan pendekatan OP dengan yang diambil oleh salah satu solusi di sini. Loop shell sangat, sangat lambat. Jika Anda perlu lebih meyakinkan, baca ini .
terdon
Dalam hal portabilitas, tidak. Dari segi kecepatan, ya. Juga, apakah @ StéphaneChazelas alias Anda?
EKons
4
@ ΈρικΚωνσταντόπουλος Θα 'θελα :) Tidak, dia baru saja menulis 2 jawaban bagus yang relevan dengan dua utas komentar. Adapun portabilitas, dengan pengecualian (kecil) dari pendekatan perl yang hanya akan bekerja pada sesuatu seperti ~ 90% dari mesin * nix, ketiga solusi adalah portabel dan shell agnostik. Atau, oke, Anda selalu bisa membuatnya sedmenjadi sed 's/\([^_]*\).*/& \1/' fileportabilitas ekstra. Intinya adalah, Anda dapat mengandalkan awkdan sedberada di sana lebih dari yang dapat Anda andalkan cukup banyak hal lain.
terdon
2

Anda disini:

#!/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"

Keluaran:

$ 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
sumber