Đó là hành vi ký tự đại diện đáng ngạc nhiên ban đầu, vì mô tả cho *
ký tự đại diện nói:
Phù hợp với bất kỳ chuỗi, bao gồm cả chuỗi null.
... Cho đến khi bạn nhận ra khoảng thời gian đó hơi đặc biệt khi đó là ký tự đầu tiên của tên tệp. Các văn bản giới thiệu 3.5.8 Filename Expansion
nói rằng:
Khi một mẫu được sử dụng để mở rộng tên tệp, ký tự '.' ở đầu tên tệp hoặc ngay sau dấu gạch chéo phải được khớp rõ ràng, trừ khi tùy chọn shell dotglob được đặt.
"Mẫu sử dụng" của các ký tự đại diện tiền tố ./
rất hữu ích cho Xử lý các tên có dấu gạch đầu dòng trong bash shell , như Steeldo nhận xét. Nó không có tác dụng đối với việc mở rộng ký tự đại diện / tên tệp, nhưng giúp xử lý tên tệp an toàn hơn / dễ dàng hơn khi bạn tham chiếu đến chúng, nếu chúng bắt đầu bằng các ký tự mà các chương trình đó có thể hiểu sai là các tùy chọn. Ví dụ:
# I want a file named `-n`
$ touch -n
touch: invalid option -- 'n'
Try 'touch --help' for more information.
$ touch -- -n
### ok
$ touch ./-n
### ok
... và bây giờ tôi có một tệp có tên -n
, nếu tôi tình cờ lặp lại nó bằng ký tự đại diện:
for file in *n
do
echo "$file"
done
... Tôi không nhận được đầu ra!
Nhưng nếu tôi đặt tiền tố ký tự đại diện với ./
,
for file in ./*n
do
echo "$file"
done
./-n
... Tôi thấy tên tệp.
Đây là một ví dụ đơn giản cho mục đích trình diễn; xem thêm Tại sao printf tốt hơn echo? vì lý do này và những người khác. Các tiện ích khác sẽ được tăng gấp ba bởi các tùy chọn khác, vì vậy tốt hơn là trình bày tên tệp cho các tiện ích một cách an toàn nhất có thể. Nếu bạn không đặt tiền tố ký tự đại diện để "thoát" tên tệp, bạn phải "bảo vệ" các tiện ích của mình theo những cách khác; một phổ biến là báo hiệu kết thúc các tùy chọn với --
, ví dụ:
for file in *n
do
mv -- "$file" backup/"$file"
done
... sẽ chuyển -n
tên tệp một cách an toàn đến mv
(như được thấy dưới đây set -x
):
mv -- -n backup/-n
./*
là nó đảm bảo rằng các tên bắt đầu-
không được coi là tùy chọn.