Bash Đọc: Đọc danh sách được phân tách bằng dấu phẩy, phần tử cuối cùng bị bỏ qua


8

Đầu ra của lệnh dưới đây là lạ đối với tôi. Tại sao nó không trả lại cho tôi phần tử 5?

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

Tôi hy vọng '5' cũng sẽ được trả lại. Chạy GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu). Thêm dấu phẩy hoạt động, nhưng dữ liệu đầu vào của tôi không có dấu phẩy. Tui bỏ lỡ điều gì vậy?

Câu trả lời:


12

Với read, -dđược sử dụng để chấm dứt các dòng đầu vào (nghĩa là không tách các dòng đầu vào). "Dòng" cuối cùng của bạn không chứa dấu kết thúc, do đó readtrả về false trên EOF và vòng lặp thoát (mặc dù giá trị cuối cùng đã được đọc).

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

(Ngay cả với -d, readcũng sử dụng $IFS, hấp thụ khoảng trắng bao gồm cả dấu vết \ntrên giá trị cuối cùng sẽ xuất hiện bằng các phương thức khác như readarray)

Câu hỏi thường gặp về Bash thảo luận về vấn đề này và cách xử lý các trường hợp tương tự khác nhau:


8
Tôi đoán người ta có thể làm read -d, i || [[ -n $i ]]một la while read -r line || [[ -n $line ]]nghĩa là gì?
Steeldo

8

Như các câu trả lời khác, -dlà một ký tự cuối dòng, không phải là dấu phân cách trường. Bạn có thể làm

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

5

Từ người đàn ông:

-d delim

Ký tự đầu tiên của delim được sử dụng để chấm dứt dòng đầu vào, thay vì dòng mới.

Phần tử 5 của bạn không có dấu phân cách (dấu phẩy), vì vậy nó sẽ không được đọc.


Vì vậy, cách khắc phục tốt nhất là đặt dấu phẩy khác sau đầu vào?
Karlo

3
Cách khắc phục tốt nhất có thể là xử lý dữ liệu bằng một cái gì đó không phải là vỏ . Vì những người trả lời ở đây đã giải quyết câu hỏi hiện tại, bạn có thể xem xét một câu hỏi riêng thể hiện mục tiêu lớn hơn của bạn.
Jeff Schaller

3

Những gì bạn đang thấy là cùng một hành vi (và vì cùng một lý do) như Tại sao vòng lặp 'while' này không nhận ra dòng cuối cùng?

Như trong trường hợp đó, bạn có thể sửa đổi hành vi bằng cách thêm một bài kiểm tra bổ sung vào điều kiện chấm dứt vòng lặp, như sau

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

Ví dụ.

$ echo '0,1,2,3,4,5' | while read -d, i || [[ -n $i ]]; do echo $i; done
0
1
2
3
4
5
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.