Các nullglob
tùy chọn (mà BTW là một zsh
sáng chế, chỉ thêm vào năm sau để bash
( 2.0
)) sẽ không được lý tưởng trong một số trường hợp. Và ls
là một ví dụ tốt:
ls *.txt
Hoặc tương đương chính xác hơn của nó:
ls -- *.txt
Với nullglob
on sẽ chạy ls
mà không có đối số nào được coi là ls -- .
(liệt kê thư mục hiện tại) nếu không có tệp nào khớp, điều này có thể tệ hơn so với việc gọi ls
với một *.txt
đối số là nghĩa đen .
Bạn sẽ gặp vấn đề tương tự với hầu hết các tiện ích văn bản:
grep foo *.txt
Sẽ tìm kiếm foo
trên stdin nếu không có txt
tập tin.
Một mặc định hợp lý hơn và một trong các csh, tcsh, zsh hoặc fish 2.3+ (và các shell Unix đầu tiên) là hủy bỏ lệnh hoàn toàn nếu toàn cầu không khớp.
bash
(kể từ phiên bản 3) có một failglob
tùy chọn cho điều đó (thú vị với cuộc thảo luận này, vì trái với ash
, AT & T ksh
hoặc zsh
, bash
không hỗ trợ phạm vi địa phương cho các tùy chọn (mặc dù điều đó thay đổi trong 4.4), tùy chọn đó khi được bật trên toàn cầu sẽ phá vỡ một số điều như các hàm hoàn thành bash).
Lưu ý rằng csh và tcsh là hơi khác nhau từ zsh
, fish
hoặc bash -O failglob
trong các trường hợp như:
ls -- *.txt *.html
Nơi bạn cần tất cả các khối để không khớp để lệnh bị hủy. Chẳng hạn, nếu có một tệp txt và không có tệp html, thì đó là:
ls -- file.txt
Bạn có thể có hành vi đó zsh
với setopt cshnullglob
mặc dù một cách hợp lý hơn để thực hiện nó zsh
sẽ là sử dụng một quả địa cầu như:
ls -- *.(txt|html)
Trong zsh
và ksh93
, bạn cũng có thể áp dụng nullglob trên cơ sở toàn cầu, đây là cách tiếp cận hiệu quả hơn nhiều so với sửa đổi cài đặt toàn cầu:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
sẽ tạo ra một mảng trống nếu không có txt
tệp thay vì thất bại lệnh có lỗi (hoặc biến nó thành một mảng với một *.txt
đối số bằng chữ với các shell khác).
Các phiên bản fish
trước 2.3 sẽ hoạt động như thế bash -O nullglob
nhưng đưa ra cảnh báo khi tương tác khi toàn cầu không khớp. Kể từ 2.3, nó hoạt động giống như zsh
ngoại trừ các khối được sử dụng trong for
, set
hoặc count
.
Bây giờ, trên ghi chú lịch sử, hành vi đã thực sự bị phá vỡ bởi vỏ Bourne. Trong các phiên bản trước của Unix, việc tạo hình được thực hiện thông qua trình /etc/glob
trợ giúp và người trợ giúp đó đã hành xử như csh
sau: nó sẽ không thực hiện được lệnh nếu không có bất kỳ khối nào khớp với bất kỳ tệp nào và loại bỏ các khối không có kết quả trùng khớp.
Vì vậy, tình huống chúng ta gặp phải hôm nay là do một quyết định tồi tệ được đưa ra trong vỏ Bourne.
Lưu ý rằng shell Bourne (và shell C) đi kèm với một tính năng Unix mới khác: môi trường. Điều đó có nghĩa là mở rộng biến (tiền thân của nó chỉ có $1
, $2
... tham số vị trí). Shell Bourne cũng giới thiệu thay thế lệnh.
Một quyết định thiết kế kém khác của shell Bourne là thực hiện toàn cầu hóa (và tách) khi mở rộng các biến và thay thế lệnh (có thể để tương thích ngược với shell Thompson, nơi echo $1
vẫn sẽ gọi /etc/glob
nếu $1
chứa các ký tự đại diện (nó giống như mở rộng macro tiền xử lý ở đó, như trong giá trị mở rộng đã được phân tích cú pháp lại dưới dạng mã shell)).
Không có những quả cầu không phù hợp có nghĩa là:
pattern='a.*b'
grep $pattern file
sẽ thất bại lệnh (trừ khi có một số a.whateverb
tệp trong thư mục hiện tại). csh
(cũng thực hiện toàn cầu khi mở rộng biến) không thực hiện được lệnh trong trường hợp đó (và tôi cho rằng tốt hơn là để lại một lỗi không hoạt động ở đó, ngay cả khi nó không tốt như không thực hiện toàn cầu như trong zsh
).