Saya bermain-main dengan ekspansi, dan saya memperhatikan perilaku yang aneh. Saya mencoba melakukan:
echo ./*.txt
Dan saya tidak punya file .txt di direktori saya saat ini. Output yang saya dapatkan adalah:
./*.txt
Saya hanya ingin tahu: Mengapa saya mendapatkan ini? Saya berharap tidak mendapatkan hasil.
PS: Ketika saya punya .txt
file, ekspansi itu ditafsirkan dengan benar. Dengan kata lain, katakan saya punya file,, smthn.txt
gema sebenarnya bergema current_directory/smthn.txt
.
sumber
shopt -s nullglob
akan menghasilkan string kosong untuk pola yang tidak cocok danshopt -u nullglob
(pengaturan standar) akan menghasilkan pola itu sendiri.Jika
nullglob
default, banyak perintah akan berperilaku tidak terduga, karena itu (mungkin sayangnya) perintah yang memperlakukan kasus nol argumen nama file dengan cara yang berbeda secara kualitatif dari kasus satu atau lebih argumen nama file.Misalkan Anda telah mengaktifkan
nullglob
(shopt -s nullglob
) dan Anda berada di direktori di mana tidak ada file yang cocok*.txt
. Maka*.txt
memang akan berkembang menjadi nol - bukan bidang kosong, tapi tidak ada bidang sama sekali - seperti yang Anda harapkan. Tetapi itu akan memiliki hasil ini:ls *.txt
akan mencantumkan semua file di direktori saat ini (kecuali file tersembunyi), karena itulah yangls
terjadi ketika Anda tidak memberikan argumen nama file apa pun.cat *.txt
akan membaca dari input standar , karena ketikacat
tidak memiliki argumen nama file, seolah-olah Anda berlaricat -
. Jika berjalan secara interaktif, ia menunggu input. Banyak perintah berperilaku seperti ini.cp *.txt dest/
akan gagal dengan kesalahancp: missing destination file operand after 'dest/'
. Ini bukan bencana, tetapi membingungkan dan sangat berbeda dari keberhasilan diam-diam yang mungkin diinginkan.file *.txt
, dan berbagai program lain tanpa perilaku khusus untuk argumen argumen tanpa nama file, akan tetap gagal dengan pesan kesalahan atau penggunaan saat tidak ada yang diteruskan.printf 'Got file: "%s"\n' *.txt
akan mencetakGot file: ""
bukan apa-apa.*
,?
dan[
yang tidak dimaksudkan untuk diperluas oleh shell akan lebih sering menghasilkan hasil yang jelas salah, tapi cara-cara yang mungkin sulit untuk mencari tahu. Misalnya, jika tidak ada nama file di direktori saat ini dimulaigedit
, makaapt list gedit*
(di manaapt list 'gedit*'
dimaksudkan) akan menjadi adilapt list
dan daftar semua paket yang tersedia.Jadi ada baiknya Anda tidak mendapatkan perilaku ini tanpa memintanya. Mungkin situasi praktis paling umum yang sebenarnya disederhanakan
nullglob
adalahfor f in *.txt
. Lihat juga pertanyaan ini (yang terkait dengan jawaban Sergiy Kolodyazhnyy ).Pertanyaan yang lebih sulit untuk dijawab adalah mengapa -
failglob
di mana kesalahan ekspansi memiliki glob yang tidak cocok dengan file apa pun - bukanlah default di bash. Saya percaya jawaban Sergiy Kolodyazhnyy menangkap alasan ini bahkan tanpa mengatasinya secara langsung. Mempertahankan gumpalan yang tidak meluas tanpa menghasilkan kesalahan ekspansi adalah (mungkin sayangnya) perilaku standar, dan juga merupakan perilaku tradisional, dan dengan demikian diharapkan. Meskipun bash tidak berusaha untuk sepenuhnya mematuhi POSIX kecuali jika dipanggil dengan namash
atau melewati--posix
opsi, banyak pilihan desainnya bahkan ketika tidak dalam mode POSIX mengikuti POSIX secara langsung. Mereka harus memilih beberapa perilaku, dan ada kelemahan yang terkait dengan bertentangan dengan harapan pengguna.Saya pikir ini adalah aspek yang paling tidak berpengaruh secara historis dari masalah ini jadi saya menyimpannya untuk yang terakhir ... tetapi perlu disebutkan bahwa ada sesuatu yang sedikit aneh secara konseptual tentang
nullglob
perilaku.nullglob
kelihatannya anggun pada mulanya karena, secara sintaksis , ini memperlakukan kasus nol file yang cocok tidak berbeda dari kasus satu, dua, atau nomor lainnya. Perintah yang kami jalankan, yang gumpalan meluas ke argumen, tidak cenderung memperlakukannya sama, seperti yang dijelaskan di atas. Tapi secara sintaksis ini setidaknya terasa benar, yang saya pikir adalah motivasi untuk pertanyaan Anda.Namun, ada lagi, ketidakkonsistenan yang lebih halus yang
nullglob
tidak diatasi - yang benar-benar menguatkan. Kasus zero globbing karakter ("wildcard") diperlakukan sangat berbeda dari satu, atau dua, atau nomor lainnya. Misalnya, denganshopt -s nullglob
, jikaab?d?f
tidak cocok dengan file apa pun, itu dihapus; jikaab?d
tidak cocok dengan file apa pun, itu dihapus; tetapi jikaab
tidak cocok dengan file apa pun (yaitu, jika tidak ada file yang namanya persisab
) itu masih belum dihapus. Tentu saja, itu akan menjadi bencana jika dihapus, karena mungkin tidak dimaksudkan untuk merujuk ke file yang ada di direktori saat ini sama sekali; bahkan mungkin tidak merujuk ke file. Tetapi ini masih menghilangkan harapan untuk konsistensi total.Tiga perilaku yang disediakan oleh bash - standar untuk memperlakukan gumpalan yang tidak cocok dengan file apa pun seolah-olah itu bukan gumpalan dan meneruskannya tidak diperluas, perilaku yang Anda harapkan untuk memperlakukannya (jika Anda akan memaafkan pergantian frase yang aneh ini) sebagai menandakan semua nol file yang cocok (
nullglob
), dan perilaku aman untuk menganggapnya kesalahan (failglob
) - semua mewakili pendekatan yang berbeda terhadap ambiguitas yang melekat dalam shell tidak dapat mengetahui apakah ada kata tertentu yang dimaksudkan untuk menjadi nama file. Shell melakukan ekspansi tanpa mengetahui bagaimana perintah tertentu yang Anda panggil dengannya akan memperlakukan argumen mereka.Ini adalah salah satu dari banyak contoh pemisahan keprihatinan . Dalam sistem yang desainnya mengikuti filosofi Unix, setiap bagian dimaksudkan untuk melakukan satu hal dan melakukannya dengan baik . Shell memproses teks menjadi perintah dan argumen dan menjalankan perintah itu, yang sebagian besar di luar shell itu sendiri. Ini cenderung jauh lebih bagus dan lebih fleksibel daripada sistem di mana perintah eksternal sendiri bertanggung jawab untuk melakukan transformasi tersebut (seperti dengan prosesor perintah tradisional di DOS dan Windows). Tapi kadang-kadang ada kerugiannya.
sumber
failglob
. Jadi tidak bisa default karena tidak selalu didukung.Alasan utamanya adalah karena ini adalah perilaku standar yang ditentukan oleh POSIX - standar yang mencakup bahasa perintah shell dan antara lain pencocokan pola (shell seperti
bash
,dash
shell - default Ubuntu/bin/sh
, danksh
mengikuti standar ini). Dari bagian 2.13.3 Pola yang Digunakan untuk Ekspansi Nama File :Ini tentu saja memiliki efek samping - mencocokkan nama file yang mungkin secara harfiah
*.txt
. Thenullglob
pilihan dibash
danzsh
dapat membantu: jika opsi yang diaktifkan melaluishopt -s nullglob
(dan itu tidak diaktifkan secara default yang berlaku untuk pertanyaan ini), maka globstar akan diperluas ke string kosong ketika tidak ada nama file yang cocok.ksh93
memiliki mekanisme pencocokan pola canggih sendiri yang mencapai efek yang sama~(N)*.txt
Lihat juga Mengapa nullglob tidak default?
sumber