Apa itu pemisahan kata? Mengapa ini penting dalam pemrograman shell?

16

Saya semakin bingung tentang peran kata splitting zsh. Saya belum terkena konsep ini ketika pemrograman dalam C, Python atau MATLAB, dan ini telah memicu minat saya mengapa pemisahan kata tampaknya menjadi sesuatu yang spesifik untuk pemrograman shell.

Saya telah membaca tentang pemisahan kata pada situs ini dan situs lain sebelumnya, tetapi belum menemukan penjelasan yang jelas tentang konsep ini. Wikipedia memiliki definisi pemisahan kata tetapi tampaknya tidak memiliki referensi tentang bagaimana ia berlaku untuk shell Unix.

Berikut ini contoh kebingungan saya di zsh:

Dalam Z Shell FAQ , saya membaca yang berikut:

3.1: Mengapa di $varmana var="foo bar"tidak melakukan apa yang saya harapkan?

Dalam sebagian besar turunan Bourne-shell, variabel multi-kata seperti var="foo bar" dipecah menjadi kata-kata saat diteruskan ke perintah atau digunakan dalam satu for foo in $varlingkaran. Secara default, zsh tidak memiliki perilaku itu: variabel tetap utuh. (Ini bukan bug! Lihat di bawah.) Pilihan SH_WORD_SPLITada untuk memberikan kompatibilitas.

Namun, dalam Manual Z Shell , saya membaca yang berikut:

SH_WORD_SPLIT (-y) <K> <S>

Menyebabkan pemisahan bidang dilakukan pada ekspansi parameter yang tidak dikutip. Perhatikan bahwa opsi ini tidak ada hubungannya dengan pemisahan kata. (Lihat Ekspansi Parameter.)

Mengapa mengatakan bahwa SH_WORD_SPLITmemiliki ada hubungannya dengan kata membelah? Bukankah kata pemecahan tepat tentang apa ini?

Amelio Vazquez-Reina
sumber

Jawaban:

21

Kerang awal hanya memiliki satu tipe data: string. Tapi itu umum untuk memanipulasi daftar string, biasanya ketika melewati beberapa nama file sebagai argumen untuk suatu program. Kasus penggunaan umum lainnya untuk pemisahan adalah ketika sebuah perintah mengeluarkan daftar hasil: keluaran perintah adalah sebuah string, tetapi data yang diinginkan adalah daftar string. Untuk menyimpan daftar nama file dalam suatu variabel, Anda harus memberi spasi di antara mereka. Lalu skrip shell seperti ini

files="foo bar qux"
myprogram $files

dipanggil myprogramdengan tiga argumen, ketika shell membagi string $filesmenjadi kata-kata. Pada saat itu, spasi dalam nama file dilarang atau banyak dianggap Tidak Selesai.

The Korn shell diperkenalkan array: Anda bisa menyimpan daftar string dalam variabel. Cangkang Korn tetap kompatibel dengan cangkang Bourne yang didirikan saat itu, jadi ekspansi variabel terbuka terus mengalami pemisahan kata, dan menggunakan array diperlukan beberapa overhead sintaksis. Anda akan menulis cuplikan di atas

files=(foo bar qux)
myprogram "${files[@]}"

Zsh memiliki susunan sejak awal, dan penulisnya memilih desain bahasa yang lebih waras dengan mengorbankan kompatibilitas ke belakang. Di zsh (di bawah aturan ekspansi default) $vartidak melakukan pemisahan kata; jika Anda ingin menyimpan daftar kata dalam suatu variabel, Anda harus menggunakan array; dan jika Anda benar-benar ingin pemisahan kata, Anda dapat menulis $=var.

files=(foo bar qux)
myprogram $files

Saat ini, spasi dalam nama file adalah sesuatu yang perlu Anda atasi, baik karena banyak pengguna berharap mereka bekerja dan karena banyak skrip dieksekusi dalam konteks sensitif keamanan di mana penyerang dapat mengendalikan nama file. Jadi pemisahan kata otomatis sering kali merepotkan; maka saran umum saya untuk selalu menggunakan tanda kutip ganda, yaitu menulis "$foo", kecuali Anda mengerti mengapa Anda perlu pemisahan kata dalam kasus penggunaan tertentu. (Perhatikan bahwa ekspansi variabel kosong juga mengalami globbing.)

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih Gilles, ini sangat membantu! Apakah benar mengatakan bahwa pemisahan kata secara kasar mengubah string formulir "word1 word2 word3"menjadi daftar / array formulir "word1" "word2" "word3"? Saya juga telah memperbarui OP dengan sumber kebingungan khusus di zsh.
Amelio Vazquez-Reina
1
@intrpc "Word splitting" tidak memisahkan pada kata-kata bahasa alami tetapi pada $IFSkarakter. Karenanya "pemisahan lapangan" adalah nama yang lebih baik. Tetapi "pemecahan kata" sering digunakan untuk konsep ini dalam literatur shell. Dokumentasi zsh berdalih tentang kata-kata.
Gilles 'SO- stop being evil'
1
Lihat juga rc(shell plan9, juga porting ke Unix) untuk desain yang lebih baik daripada zsh ketika datang ke variabel dan array.
Stéphane Chazelas
3

Pemisahan kata tidak benar-benar spesifik untuk shell.

Sebagian besar program yang perlu mengurai input teks menggunakan beberapa bentuk pemisahan kata sebagai langkah pertama. Hal ini dilakukan sebelum mengidentifikasi dari "kata-kata" ini, angka, operator, string, token, dan entitas serupa apa pun yang perlu mereka proses.

Apa yang spesifik dengan shell adalah bahwa mereka harus membangun dengan benar daftar argumen dari perintah yang disebut (C argc / argv, python sys.argv), termasuk meneruskan argumen dengan ruang yang disematkan, argumen kosong, pembatas kustom dan sebagainya. Banyak shell menggunakan variabel IFS untuk memungkinkan fleksibilitas di sana.

Jlliagre
sumber
3

Dalam kasus spesifik Zsh ini, pemisahan kata didefinisikan sedikit berbeda dari pemisahan bidang.

Pertimbangkan prog a b c, itu akan melewati tiga argumen tidak peduli bagaimana Anda mengatur IFS. Ini adalah pemisahan kata .

Jika Anda melakukannya A="a b c"; prog $A, itu akan melewati tiga argumen jika IFSmenyertakan spasi atau satu argumen sebaliknya. Ini adalah pemisahan bidang .

Definisi di sini halus. Apa yang ingin dikatakan dokumen Zsh adalah bahwa, meskipun Anda menonaktifkan opsi itu, prog a b cmasih akan mendapatkan argumen terpisah (yang selalu diharapkan orang).

Hot.PxL
sumber
1
Bart Schaefer, seorang pengembang zsh yang sudah lama, menegaskan bahwa memang itulah makna yang dimaksud dari teks tersebut .
Stéphane Chazelas