Tampaknya praktik normal akan menempatkan pengaturan IFS di luar loop sementara agar tidak mengulangi pengaturan untuk setiap iterasi ... Apakah ini hanya gaya "monyet lihat, monyet lakukan" seperti kebiasaan, untuk monyet ini sampai Saya membaca man read , atau apakah saya melewatkan beberapa perangkap yang halus (atau sangat jelas) di sini?
81
while IFS=X read
tidak terpecah padaX
, tetapiwhile IFS=X; read
tidak ...while
tidak masuk akal - kondisi untukwhile
ujung pada titik koma itu, jadi tidak ada loop aktual ...read
menjadi hanya perintah pertama di dalam loop satu elemen ... Atau tidak ? Bagaimana kalaudo
begitu ..?while
kondisi (sebelumdo
).IFS=
bekerja, tetapiIFS=X
tidak ... (atau mungkin saya sudah melakukan ini untuk sementara waktu .. coffee break diperlukan :)Mari kita lihat contoh, dengan beberapa teks input yang dibuat dengan cermat:
Itu dua baris, yang pertama dimulai dengan spasi dan diakhiri dengan garis miring terbalik. Pertama, mari kita lihat apa yang terjadi tanpa tindakan pencegahan di sekitarnya
read
(tetapi gunakanprintf '%s\n' "$text"
untuk mencetak dengan hati-hati$text
tanpa risiko ekspansi). (Di bawah,$
adalah prompt shell.)read
memakan backslash: backslash-newline menyebabkan baris baru diabaikan, dan backslash-apa pun mengabaikan backslash pertama. Untuk menghindari backslash diperlakukan secara khusus, kami menggunakanread -r
.Itu lebih baik, kami memiliki dua garis seperti yang diharapkan. Dua baris hampir berisi konten yang diinginkan: ruang ganda di antara
hello
danworld
telah dipertahankan, karena berada dalamline
variabel. Di sisi lain, ruang awal dimakan. Itu karenaread
membaca banyak kata saat Anda meneruskan variabel, kecuali bahwa variabel terakhir berisi sisa baris - tetapi masih dimulai dengan kata pertama, yaitu spasi awal dibuang.Jadi, untuk membaca setiap baris secara harfiah, kita perlu memastikan bahwa tidak ada pemisahan kata yang terjadi. Kami melakukan ini dengan mengatur
IFS
variabel ke nilai kosong.Perhatikan bagaimana kami mengatur
IFS
secara spesifik untuk durasiread
built-in . TheIFS= read -r line
set variabel lingkunganIFS
(untuk nilai kosong) khusus untuk pelaksanaanread
. Ini adalah turunan dari sintaks perintah sederhana umum : urutan penugasan variabel (kemungkinan kosong) diikuti oleh nama perintah dan argumennya (juga, Anda bisa melempar pengalihan kapan saja). Karenaread
built-in, variabel tidak pernah benar-benar berakhir di lingkungan proses eksternal; namun nilai dari$IFS
apa yang kami tetapkan di sana selamaread
eksekusi long . Perhatikan bahwaread
itu bukan built-in khusus , sehingga tugas tidak hanya berlangsung selama durasinya.Karenanya kami berhati-hati untuk tidak mengubah nilai
IFS
instruksi lain yang mungkin bergantung padanya. Kode ini akan berfungsi tidak peduli apa kode yang ditetapkan diIFS
awal, dan tidak akan menimbulkan masalah jika kode di dalam loop bergantungIFS
.Berbeda dengan potongan kode ini, yang mencari file di jalur yang dipisahkan titik dua. Daftar nama file dibaca dari file, satu nama file per baris.
Jika loop itu
while IFS=; read -r name; do …
, makafor dir in $PATH
tidak akan terpecah$PATH
menjadi komponen yang dipisahkan oleh titik dua. Jika kode ituIFS=; while read …
, akan lebih jelas lagi bahwaIFS
tidak diatur ke:
dalam loop body.Tentu saja, akan mungkin untuk mengembalikan nilai
IFS
setelah dieksekusiread
. Tetapi itu akan membutuhkan mengetahui nilai sebelumnya, yang merupakan upaya ekstra.IFS= read
adalah cara sederhana (dan, mudah, juga cara terpendek).¹ Dan, jika
read
diinterupsi oleh sinyal yang terperangkap, mungkin saat jebakan mengeksekusi - ini tidak ditentukan oleh POSIX dan tergantung pada shell dalam praktiknya.sumber
while IFS= read
(tanpa tanda titik koma=
) bukanlah bentuk khusus dariwhile
atauIFS
atauread
.. Konstruk itu generik: yaitu.anyvar=anyvalue anycommand
. Kurangnya;
setelah pengaturananyvar
membuat lingkupanyvar
lokal menjadianycommand
.. Loop sementara - lakukan / dilakukan adalah 100% tidak terkait dengan lingkup lokalany_var
.Terlepas dari (sudah diklarifikasi)
IFS
perbedaan scoping antarawhile IFS='' read
,IFS=''; while read
danwhile IFS=''; read
idiom (per-perintah vs script / shell-lebarIFS
variabel scoping), pelajaran dibawa pulang adalah bahwa Anda kehilangan terkemuka dan spasi dari garis masukan jika variabel IFS diatur ke (mengandung a) ruang.Ini dapat memiliki konsekuensi yang cukup serius jika jalur file sedang diproses.
Oleh karena itu pengaturan variabel IFS ke string kosong sama sekali bukan ide yang buruk karena hal itu memastikan bahwa spasi spasi awal dan akhir garis tidak dilucuti.
Lihat juga: Bash, baca baris demi baris dari file, dengan IFS
sumber
Terinspirasi oleh jawaban Yuzem
Jika Anda ingin mengatur
IFS
ke karakter yang sebenarnya, ini bekerja untuk sayasumber