Menggunakan "saat membaca ..." dalam skrip linux

34

Bisakah seseorang tolong jelaskan bagaimana kode berikut bekerja?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

Secara khusus, saya ingin tahu mengapa output dari loop ini 3 4 5 6 2 1, bukan 3 2 1dan 6 5 4pada dua baris terpisah? Sepertinya saya tidak bisa membungkus pikiran saya di sekitarnya ...

linuxgringo
sumber

Jawaban:

41

readmembaca seluruh baris dari input standar, membagi baris menjadi bidang dan menetapkan bidang ini ke variabel yang diberikan. Jika ada lebih banyak potongan daripada variabel, potongan yang tersisa ditugaskan ke variabel terakhir.

Dalam kasus Anda $aditugaskan 1, $bditugaskan 2dan $csisanya 3 4 5 6.

Florian Diesch
sumber
Florian terima kasih! Sekarang masuk akal ... Untuk beberapa alasan saya pikir spasi akan membatasi setiap pembacaan variabel, tetapi ternyata tidak. Saya menghargai bantuan Anda!!
linuxgringo
24

Menulis ulang loop dengan cara ini mengungkapkan apa yang terjadi:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

Ini memberi, sebagai hasilnya:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

Perhatikan dulu bahwa hanya satu perintah gema yang dijalankan. Jika dijalankan lebih dari satu kali, Anda akan, antara lain, melihat (iteration beginning)dan (iteration ending)substring dicetak lebih dari sekali.

Ini untuk mengatakan bahwa memiliki whileloop di sini tidak benar-benar mencapai apa pun. The readbuiltin membaca spasi dipisahkan teks 1 ke masing-masing variabel tertentu. Input ekstra ditambahkan ke bagian akhir variabel terakhir yang ditentukan. 2 Dengan demikian variabel adan bmengambil nilai-nilai 1dan 2masing - masing, sementara cmengambil nilai 3 4 5 6.

Ketika kondisi loop ( while read a b c) dievaluasi untuk kedua kalinya, tidak ada lagi input yang tersedia dari pipa (kami hanya memipipkannya satu baris teks), sehingga readperintah mengevaluasi ke false sebagai ganti true dan loop berhenti (sebelum pernah menjalankan tubuh kedua kalinya).

1 : Untuk teknis dan spesifik, yang readbuiltin , ketika melewati nama variabel sebagai argumen, membaca masukan, membelah menjadi terpisah "kata" ketika pertemuan IFS spasi (lihat juga pertanyaan ini dan artikel ini ).

2 : readPerilaku macet bidang input tambahan ke variabel terakhir yang ditentukan pada awalnya tidak intuitif untuk banyak skrip. Menjadi lebih mudah untuk dipahami ketika Anda mempertimbangkan bahwa, seperti jawaban Florian Diesch mengatakan , readakan selalu (mencoba) membaca seluruh baris - dan itu readdimaksudkan agar dapat digunakan baik dengan dan tanpa loop.

Eliah Kagan
sumber
Eliah, terima kasih telah meluangkan waktu untuk menjelaskan semua detailnya. Saya menduga itu whiletidak memenuhi tujuan normal dalam contoh ini, tetapi kemudian readperintah itu mengusir saya ... Entah bagaimana, saya menafsirkannya sebagai "sementara read a b ctidak salah, lakukan echo ...". Terima kasih telah menjelaskan cara kerjanya. Saya menemukan kode ini kemarin dan tahu itu akan mengganggu saya sampai saya menemukan
jawabannya
@linuxgringo Sebenarnya, tubuh loop yang dieksekusi setiap kali read a b cmengevaluasi ke benar, dan kondisi loop ( read a b c) tidak menjalankan lebih dari sekali. Bit itu hanya bernilai true pertama kali. Kali ke-2, tidak ada lagi input untuk dibaca dari pipa, sehingga akhir file ditemui, menyebabkan readkembali salah . (Lihat bagian terakhir dari output help read, pada "Status Keluar," untuk perincian, mencatat bahwa, dalam skrip shell, nol berarti benar dan bukan nol berarti salah.) Jika Anda mengirim lebih dari satu baris input ke while read ..., badan loop akan dieksekusi beberapa kali.
Eliah Kagan