bash mengubah perilakunya tergantung pada nilai variabel "IFS"

18

Ketika saya mengatur IFSvariabel ke spasi, bashmemperlakukan beberapa ruang sebagai satu ruang ( myprogramadalah program yang mencetak argumen baris perintah yang diterimanya):

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world

Tetapi ketika saya mengatur IFSvariabel ke koma, bashtidak memperlakukan beberapa koma sebagai satu koma:

IFS=","
x="hello,,,hi,,,world"
./myprogram $x
argv[1] = hello
argv[2] = 
argv[3] = 
argv[4] = hi
argv[5] = 
argv[6] = 
argv[7] = world

Mengapa demikian?

pengguna267935
sumber
Hanya untuk referensi, "IFS" berarti Pemisah Bidang Internal .
pr1268

Jawaban:

21

Ini didokumentasikan dalam man bash. Satu kejadian karakter apa pun di IFS yang bukan spasi putih membatasi bidang.

Dari man bash:

Shell memperlakukan setiap karakter IFS sebagai pembatas, dan membagi hasil ekspansi lainnya menjadi kata-kata menggunakan karakter ini sebagai terminator bidang. Jika IFS tidak disetel, atau nilainya persis <space><tab><newline>, default, maka urutan <space>, <tab>dan <newline>pada awal dan akhir dari hasil ekspansi sebelumnya diabaikan, dan setiap urutan karakter IFS tidak di awal atau akhir berfungsi untuk membatasi kata-kata. Jika IFS memiliki nilai selain dari default, maka urutan spasi spasi karakter, tab, dan baris baru diabaikan pada awal dan akhir kata, selama karakter spasi dalam nilai IFS (karakter spasi IFS ). Setiap karakter dalam IFS yang bukan spasi IFS, bersama dengan karakter spasi IFS yang berdekatan, membatasi bidang. Urutan karakter spasi putih IFS juga diperlakukan sebagai pembatas. Jika nilai IFS adalah nol, tidak ada pemisahan kata. [Penekanan ditambahkan.]

Contoh: pemisahan bidang

Jika IFS tidak memiliki karakter spasi, maka spasi putih disertakan dalam bidang:

$ ( IFS=',' x='one , two,three'; printf "<%s>\n" $x )
<one >
< two>
<three>

Jika IFS memiliki kosong dan koma, maka urutan kosong, diikuti oleh koma, diikuti oleh urutan kosong diperlakukan sebagai pembatas tunggal:

$ ( IFS=' ,' x='one , two,three'; printf "<%s>\n" $x )
<one>
<two>
<three>

Urutan koma ditafsirkan sebagai urutan bidang kosong:

$ ( IFS=' ,' x='one,,,two,three'; printf "<%s>\n" $x )
<one>
<>
<>
<two>
<three>

Contoh: memimpin dan mengikuti spasi

Jika IFS tidak mengandung spasi putih, maka spasi putih apa pun yang memimpin dan tertinggal disimpan di bidang:

$ ( IFS=',' x='  one , two,three  ,'; printf "<%s>\n" $x )
<  one >
< two>
<three  >

Jika IFS memang mengandung blanko, maka setiap blanko leading atau trailing dihapus:

$ ( IFS=' ,' x='  one , two,three  ,'; printf "<%s>\n" $x )
<one>
<two>
<three>
John1024
sumber
mungkin juga perlu ditekankan "maka urutan spasi spasi karakter, tab, dan baris spasi diabaikan pada awal dan akhir kata, selama karakter spasi spasi dalam nilai IFS"
Jeff Schaller
@ JeffSchaller Ide bagus: Saya baru saja menambahkan bagian tentang itu.
John1024
bagaimana jika Anda memiliki file tab-terpisah dengan beberapa nilai yang hilang? yaitu Anda tidak ingin urutan tab diperlakukan sebagai satu tab. Juga, bidang berisi koma jadi tidak bisa menggunakannya sebagai pembatas. Apakah satu-satunya solusi untuk menggunakan pembatas lain (bukan tab)?
Davos
@Davos Untuk data dengan masing-masing bidang dibatasi oleh satu tab, mungkin lebih alami untuk menggunakan alat lain yang menangani ini dengan mudah seperti awkdengan -F'\t'opsi atau cut. Atau, jika Anda memiliki versi terbaru bash, Anda mungkin dapat menguraikan bidang menggunakan readarraydengan -d$'\t'opsi.
John1024