Bash Read: Membaca daftar yang dipisahkan koma, elemen terakhir tidak terjawab

8

Output dari perintah di bawah ini aneh bagi saya. Mengapa itu tidak memberi saya kembali elemen 5?

$ echo '0,1,2,3,4,5' | while read -d, i; do echo $i; done
0
1
2
3
4

Saya harapkan '5' akan dikembalikan juga. Lari GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu). Menambahkan koma berfungsi, tetapi data input saya tidak memiliki koma. Apakah saya melewatkan sesuatu?

Karlo
sumber

Jawaban:

12

Dengan read, -ddigunakan untuk mengakhiri jalur input (yaitu untuk tidak memisahkan jalur input). "Baris" terakhir Anda tidak mengandung terminator, jadi readmengembalikan false pada EOF dan loop keluar (meskipun nilai akhir dibaca).

echo '0,1,2,3,4,5' | { while read -d, i; do echo "$i"; done; echo "last value=$i"; }

(Bahkan dengan -d, readjuga menggunakan $IFS, menyerap spasi termasuk trailing \npada nilai akhir yang akan muncul menggunakan metode lain seperti readarray)

Bash FAQ membahas ini, dan bagaimana menangani berbagai kasus serupa:

mr.spuratic
sumber
8
Saya kira orang bisa melakukan read -d, i || [[ -n $i ]]a la Apa while read -r line || [[ -n $line ]]artinya?
steeldriver
8

Sebagai jawaban lainnya menyatakan, -dadalah karakter end-of-line, bukan pemisah bidang. Anda dapat melakukan

IFS=, read -a fields <<< "1,2,3,4,5"
for i in "${fields[@]}"; do echo "$i"; done
Graham Breed
sumber
5

Dari manusia:

-d delim

Karakter pertama delim digunakan untuk mengakhiri jalur input, bukan baris baru.

Elemen 5 Anda tidak memiliki pembatas (koma), sehingga tidak akan dibaca.

Siva
sumber
Jadi perbaikan terbaik adalah meletakkan koma lain setelah input?
Karlo
3
The memperbaiki terbaik mungkin untuk mengolah data dengan sesuatu yang lain dari shell . Karena para penjawab di sini telah menjawab pertanyaan saat ini, Anda dapat mempertimbangkan pertanyaan terpisah yang menunjukkan tujuan Anda yang lebih besar.
Jeff Schaller
3

Apa yang Anda lihat adalah perilaku yang sama (dan untuk alasan yang sama) seperti Mengapa loop 'sementara' ini tidak mengenali baris terakhir?

Seperti dalam kasus itu, Anda dapat memodifikasi perilaku dengan menambahkan tes tambahan ke kondisi terminasi loop, sebagai berikut

while read -d, i || [[ -n $i ]]; do ...

Ex.

$ echo '0,1,2,3,4,5' | while read -d, i || [[ -n $i ]]; do echo $i; done
0
1
2
3
4
5
Steeldriver
sumber