Di sebagian besar shell nullglob
bukan default. Artinya, misalnya, jika Anda menjalankan perintah ini
ls *
di direktori kosong, itu akan memperluas *
glob menjadi *
. literal , alih-alih ke daftar argumen kosong. Ada cara untuk mengubah perilaku itu, sehingga *
di direktori kosong akan mengembalikan daftar argumen kosong, yang tampaknya lebih intuitif.
Jadi, apakah ada alasan mengapa nullglob
dinonaktifkan secara default? Jika ya, apa alasannya?
Jawaban yang Diterima:
nullglob
opsi (yang BTW adalah zsh
penemuan, hanya ditambahkan beberapa tahun kemudian ke bash
(2.0
)) tidak akan ideal dalam beberapa kasus. Dan ls
adalah contoh yang bagus:
ls *.txt
Atau padanan yang lebih tepat:
ls -- *.txt
Dengan nullglob
pada akan menjalankan ls
tanpa argumen yang diperlakukan sebagai ls -- .
(daftar direktori saat ini) jika tidak ada file yang cocok, yang mungkin lebih buruk daripada memanggil ls
dengan *.txt
literal sebagai argumen.
Anda akan memiliki masalah serupa dengan sebagian besar utilitas teks:
grep foo *.txt
Akan mencari foo
di stdin jika tidak ada txt
berkas.
Default yang lebih masuk akal, dan salah satu dari csh, tcsh, zsh atau fish 2.3+ (dan shell Unix awal) adalah membatalkan perintah sama sekali jika glob tidak cocok.
bash
(sejak versi 3) memiliki failglob
opsi untuk itu (menarik untuk diskusi ini, karena bertentangan dengan ash
, AT&T ksh
atau zsh
, bash
tidak mendukung cakupan lokal untuk opsi (meskipun itu berubah di 4.4), opsi tersebut ketika diaktifkan secara global akan merusak beberapa hal seperti fungsi penyelesaian bash).
Perhatikan bahwa csh dan tcsh sedikit berbeda dari zsh
, fish
atau bash -O failglob
dalam kasus seperti:
ls -- *.txt *.html
Di mana Anda membutuhkan semua gumpalan untuk tidak cocok agar perintah dibatalkan. Misalnya, jika ada satu file txt dan tidak ada file html, itu menjadi:
ls -- file.txt
Anda bisa mendapatkan perilaku itu dengan zsh
dengan setopt cshnullglob
meskipun cara yang lebih masuk akal untuk melakukannya di zsh
akan menggunakan gumpalan seperti:
ls -- *.(txt|html)
Dalam zsh
dan ksh93
, Anda juga dapat menerapkan nullglob berdasarkan per-glob, yang merupakan pendekatan yang jauh lebih waras daripada memodifikasi pengaturan global:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
akan membuat array kosong jika tidak ada txt
file alih-alih gagal perintah dengan kesalahan (atau menjadikannya array dengan satu *.txt
argumen literal dengan shell lain).
Versi fish
sebelum 2.3 akan berfungsi seperti bash -O nullglob
tetapi beri peringatan saat interaktif ketika gumpalan tidak cocok. Sejak 2.3, ini berfungsi seperti zsh
kecuali gumpalan yang digunakan dalam for
, set
atau count
.
Sekarang, pada catatan sejarah, perilaku itu sebenarnya rusak oleh cangkang Bourne. Pada versi Unix sebelumnya, globbing dilakukan melalui /etc/glob
helper dan helper itu berperilaku seperti csh
:perintah akan gagal jika tidak ada gumpalan yang cocok dengan file apa pun dan hapus gumpalan yang tidak cocok jika sebaliknya.
Jadi situasi yang kita hadapi saat ini adalah karena keputusan buruk yang dibuat di Bourne shell.
Perhatikan bahwa shell Bourne (dan shell C) datang dengan fitur Unix baru lainnya:lingkungan. Itu berarti ekspansi variabel (pendahulunya hanya memiliki $1
, $2
... parameter posisi). Shell Bourne juga memperkenalkan substitusi perintah.
Keputusan desain buruk lainnya dari Bourne shell adalah melakukan globbing (dan splitting) pada perluasan variabel dan substitusi perintah (mungkin untuk kompatibilitas mundur dengan shell Thompson di mana echo $1
masih akan memanggil /etc/glob
jika $1
berisi wildcard (itu lebih seperti ekspansi makro pra-prosesor di sana, seperti dalam nilai yang diperluas diuraikan lagi sebagai kode shell)).
Gumpalan gagal yang tidak cocok akan berarti misalnya bahwa:
pattern='a.*b'
grep $pattern file
akan gagal perintah (kecuali ada beberapa a.whateverb
file di direktori saat ini). csh
(yang juga melakukan globbing pada ekspansi variabel) tidak gagal perintah dalam kasus itu (dan saya berpendapat itu lebih baik daripada meninggalkan bug yang tidak aktif di sana, bahkan jika itu tidak sebagus tidak melakukan globbing sama sekali seperti di zsh
).