Tôi đã mong đợi để không nhận được bất kỳ đầu ra.
Nếu nullglob
là mặc định, nhiều lệnh sẽ hoạt động khá bất ngờ, vì thông thường (có lẽ không may) các lệnh xử lý trường hợp đối số tên tệp bằng 0 theo cách khác về mặt chất lượng so với trường hợp của một hoặc nhiều đối số tên tệp.
Giả sử bạn đã bật nullglob
( shopt -s nullglob
) và bạn đang ở trong một thư mục không có tệp nào khớp *.txt
. Sau đó, *.txt
thực sự sẽ mở rộng thành không có gì - không phải là một trường trống, nhưng không có trường nào cả - như bạn mong đợi. Nhưng điều đó sẽ có những kết quả này:
ls *.txt
sẽ liệt kê tất cả các tệp trong thư mục hiện tại (ngoại trừ các tệp bị ẩn), vì đó là những gì ls
khi bạn không vượt qua bất kỳ đối số tên tệp nào.
cat *.txt
sẽ đọc từ đầu vào tiêu chuẩn , bởi vì khi cat
không có đối số tên tệp, nó như thể bạn đã chạy cat -
. Nếu chạy tương tác, nó ngồi xung quanh chờ đầu vào. Nhiều lệnh hành xử theo cách này.
cp *.txt dest/
sẽ thất bại với lỗi cp: missing destination file operand after 'dest/'
. Đây không phải là một thảm họa, nhưng nó khó hiểu và hoàn toàn khác với thành công thầm lặng có lẽ là mong muốn.
file *.txt
và nhiều chương trình khác không có hành vi đặc biệt đối với trường hợp không có đối số tên tệp, vẫn không thành công với lỗi hoặc thông báo sử dụng khi không có thông báo nào được thông qua.
- Ngay cả những trường hợp trực giác cảm thấy như họ nên làm việc thường sẽ không.
printf 'Got file: "%s"\n' *.txt
sẽ in Got file: ""
thay vì không có gì.
- Thất bại tình cờ để báo xuất hiện của
*
, ?
và [
rằng không có ý định để được mở rộng bằng vỏ thường xuyên hơn sẽ tạo ra kết quả rõ ràng là sai, nhưng theo những cách mà có thể khó khăn để tìm ra. Ví dụ: nếu không có tên tệp trong thư mục hiện tại bắt đầu gedit
, thì apt list gedit*
(nơi apt list 'gedit*'
được dự định) sẽ trở thành chính xác apt list
và liệt kê tất cả các gói có sẵn.
Vì vậy, thật tốt khi bạn không có hành vi này mà không yêu cầu nó. Có lẽ tình huống thực tế phổ biến nhất thực sự được đơn giản hóa nullglob
là for f in *.txt
. Xem thêm câu hỏi này (mà câu trả lời của Sergiy Kolodyazhnyy liên quan đến).
Câu hỏi khó hơn để trả lời là tại sao failglob
- ở đâu đó là lỗi mở rộng để có một quả cầu không khớp với bất kỳ tệp nào - không phải là mặc định trong bash. Tôi tin rằng câu trả lời của Sergiy Kolodyazhnyy đã nắm bắt được lý do cho việc này ngay cả khi không giải quyết trực tiếp. Giữ lại các khối lượng chưa được mở rộng mà không tạo ra lỗi mở rộng (có lẽ không may) là hành vi được tiêu chuẩn hóa, và nó cũng là hành vi truyền thống, và do đó, được mong đợi. Mặc dù bash không cố gắng hoàn toàn tuân thủ POSIX trừ khi được gọi bằng tên sh
hoặc thông qua --posix
tùy chọn, nhiều lựa chọn thiết kế của nó ngay cả khi không ở chế độ POSIX theo trực tiếp POSIX. Họ đã phải chọn một số hành vi và có những nhược điểm liên quan đến việc đi ngược lại mong đợi của người dùng.
Tôi nghĩ rằng đây là khía cạnh ít ảnh hưởng nhất trong lịch sử của vấn đề nên tôi đã lưu nó lần cuối ... nhưng điều đáng nói là có một điều gì đó hơi kỳ quặc về mặt nullglob
hành vi.
nullglob
Thoạt nhìn có vẻ thanh lịch bởi vì, về mặt cú pháp , nó xử lý trường hợp các tệp không khớp không khác với trường hợp của một, hai hoặc bất kỳ số nào khác. Các lệnh chúng ta chạy, mà các khối được mở rộng thành các đối số, không có xu hướng đối xử với chúng giống như chi tiết ở trên. Nhưng về mặt cú pháp thì điều này ít nhất cảm thấy đúng, mà tôi nghĩ là động lực cho câu hỏi của bạn.
Tuy nhiên, có một sự mâu thuẫn khác, tinh tế hơn nullglob
không giải quyết được - đó là nó thực sự khuếch đại. Trường hợp các ký tự toàn cầu bằng không ("ký tự đại diện") được xử lý hoàn toàn khác với trường hợp của một hoặc hai hoặc bất kỳ số nào khác. Ví dụ, với shopt -s nullglob
, nếu ab?d?f
không khớp với bất kỳ tệp nào, nó sẽ bị xóa; nếu ab?d
không khớp với bất kỳ tập tin nào, nó sẽ bị xóa; nhưng nếu ab
không khớp với bất kỳ tệp nào (nghĩa là, nếu không có tệp nào có tên chính xác ab
) thì nó vẫn không bị xóa. Tất nhiên, nó sẽ là một thảm họa nếu nó bị xóa, bởi vì nó có thể không có ý định tham khảo một tệp hiện có trong thư mục hiện tại; nó thậm chí có thể không đề cập đến một tập tin. Nhưng điều này vẫn loại bỏ bất kỳ hy vọng cho sự nhất quán.
Ba hành vi bash cung cấp - mặc định đối xử với các khối u không khớp với bất kỳ tệp nào như thể chúng không phải là các khối và chuyển chúng chưa được mở rộng, hành vi mà bạn mong đợi khi xử lý chúng (nếu bạn bỏ qua cụm từ kỳ quặc này) như biểu thị tất cả số không của các tệp khớp với ( nullglob
) và hành vi an toàn khi xem xét chúng là lỗi ( failglob
) - tất cả đều thể hiện các cách tiếp cận khác nhau đối với sự mơ hồ vốn có trong vỏ không thể biết liệu có bất kỳ từ cụ thể nào được dự định là tên tệp. Shell thực hiện các mở rộng của nó mà không có kiến thức về cách các lệnh cụ thể mà bạn gọi với nó sẽ xử lý các đối số của chúng.
Đây là một trong nhiều trường hợp phân tách mối quan tâm . Trong các hệ thống có thiết kế tuân theo triết lý Unix, mỗi phần được dự định làm một việc và làm tốt . Shell xử lý văn bản thành các lệnh và đối số và gọi các lệnh đó, hầu hết trong số đó là bên ngoài chính shell. Điều này có xu hướng đẹp hơn và linh hoạt hơn nhiều so với các hệ thống mà các lệnh bên ngoài tự chịu trách nhiệm thực hiện các biến đổi đó (như với các bộ xử lý lệnh truyền thống trong DOS và Windows). Nhưng nó có nhược điểm thường xuyên của nó.
shopt -s nullglob
sẽ tạo ra các chuỗi trống cho các mẫu không khớp vàshopt -u nullglob
(cài đặt tiêu chuẩn) sẽ tự tạo ra mẫu.