Điều đó bắt đầu như một hack trong vỏ Bourne. Trong trình bao Bourne, việc tách từ IFS đã được thực hiện (sau khi mã hóa) trên tất cả các từ trong ngữ cảnh danh sách (đối số dòng lệnh hoặc các từ for
lặp vòng lặp trên). Nếu bạn có:
IFS=i var=file2.txt
edit file.txt $var
Đó là dòng thứ hai sẽ được tokenised trong 3 từ, $var
sẽ được mở rộng, và chia + glob sẽ được thực hiện trên tất cả ba chữ, vì vậy bạn sẽ kết thúc chạy ed
với t
, f
, le.txt
, f
, le2.txt
như các đối số.
Trích dẫn các phần của điều đó sẽ ngăn chặn sự phân chia + toàn cầu. Shell Bourne ban đầu nhớ các ký tự được trích dẫn bằng cách đặt bit thứ 8 vào bên trong chúng (điều này đã thay đổi sau đó khi Unix trở nên sạch 8bit, nhưng shell vẫn làm một cái gì đó tương tự như ghi nhớ byte nào được trích dẫn).
Cả hai $*
và $@
là sự kết hợp của các tham số vị trí với không gian ở giữa. Nhưng có một xử lý đặc biệt $@
khi bên trong dấu ngoặc kép. Nếu được $1
chứa foo bar
và $2
chứa baz
, "$@"
sẽ mở rộng thành:
foo bar baz
^^^^^^^ ^^^
(với ^
s ở trên chỉ ra ký tự nào có tập bit thứ 8). Trong đó khoảng trắng đầu tiên được trích dẫn (có tập bit thứ 8) nhưng không phải là khoảng trống thứ hai (khoảng trắng được thêm vào giữa các từ).
Và đó là phân tách IFS đảm nhiệm việc tách các đối số (giả sử ký tự khoảng trắng nằm trong $IFS
mặc định). Điều đó tương tự như cách $*
mở rộng trong vỏ tiền thân của nó (vỏ dựa trên vỏ Thomson, trong khi vỏ Bourne được viết từ đầu).
Điều đó giải thích tại sao trong vỏ Bourne ban đầu "$@"
sẽ mở rộng thành chuỗi rỗng thay vì không có gì cả khi danh sách các tham số vị trí trống (bạn phải làm việc với nó ${1+"$@"}
), tại sao nó không giữ các tham số vị trí trống và tại sao "$@"
không Sẽ không hoạt động khi $IFS
không chứa ký tự khoảng trắng.
Ý định là có thể chuyển danh sách các đối số nguyên văn sang một lệnh khác, nhưng điều đó không hoạt động đúng cho danh sách trống, cho các phần tử trống hoặc khi $IFS
không chứa khoảng trắng (hai vấn đề đầu tiên cuối cùng đã được sửa trong các phiên bản sau ).
Trình bao Korn (dựa trên thông số POSIX) đã thay đổi hành vi đó theo một số cách:
- Việc chia IFS chỉ được thực hiện dựa trên kết quả của các mở rộng không được trích dẫn (không phải trên các từ nghĩa đen như
edit
hoặc file.txt
trong ví dụ trên)
$*
và $@
được nối với ký tự đầu tiên của $IFS
hoặc khoảng $IFS
trắng khi trống, ngoại trừ đối với dấu "$@"
ngoặc kép, phép nối đó không được trích dẫn như trong trình bao Bourne và đối với dấu ngoặc kép "$*"
khi IFS
trống, các tham số vị trí được nối mà không có dấu phân cách.
- nó đã thêm hỗ trợ cho các mảng và
${array[@]}
${array[*]}
gợi nhớ đến Bourne $*
và $@
bắt đầu từ chỉ số 0 thay vì 1 và thưa thớt (giống như mảng kết hợp) có nghĩa là $@
không thể thực sự được coi là mảng ksh (so sánh với csh
/ rc
/ zsh
/ fish
/ yash
trong đó $argv
/ $*
là bình thường mảng).
- Các yếu tố trống được bảo tồn.
"$@"
khi $#
0 là mở rộng thành không có gì thay vì chuỗi rỗng, "$@"
hoạt động khi $IFS
không chứa khoảng trắng trừ khi IFS
trống. Một $*
không được trích dẫn mà không có ký tự đại diện sẽ mở rộng thành một đối số (trong đó các tham số vị trí được nối với khoảng $IFS
trắng ) khi trống.
ksh93 đã sửa một vài vấn đề còn lại ở trên. Trong ksh93, $*
và $@
mở rộng ra danh sách các tham số vị trí, được phân tách bất kể giá trị của $IFS
, và sau đó phân tách tiếp tục + nối tiếp + mở rộng trong ngữ cảnh danh sách, được $*
nối với byte đầu tiên (không phải ký tự) của $IFS
, "$@"
trong bối cảnh danh sách mở rộng ra danh sách của các tham số vị trí, bất kể giá trị của $IFS
. Trong ngữ cảnh không có danh sách, như trong var=$@
, $@
được nối với không gian bất kể giá trị của $IFS
.
bash
Các mảng được thiết kế sau các mảng ksh. Sự khác biệt là:
- không mở rộng cú đúp khi mở rộng không trích dẫn
- ký tự đầu tiên
$IFS
thay vì cho byte
- một số khác biệt trường hợp góc như mở rộng
$*
khi không trích dẫn trong bối cảnh không có danh sách khi $IFS
trống.
Mặc dù thông số POSIX trước đây khá mơ hồ, nhưng bây giờ ít nhiều chỉ định hành vi bash.
Nó khác với các mảng bình thường trong ksh
hoặc bash
trong đó:
- Các chỉ số bắt đầu từ 1 thay vì 0 (ngoại trừ trong
"${@:0}"
đó bao gồm $0
(không phải là tham số vị trí và trong các hàm cung cấp cho bạn tên của hàm hoặc không phụ thuộc vào trình bao và cách xác định hàm)).
- Bạn không thể chỉ định các yếu tố riêng lẻ
- nó không thưa thớt, bạn không thể hủy bỏ các yếu tố riêng lẻ
shift
có thể được sử dụng.
Trong zsh
hoặc yash
nơi các mảng là các mảng bình thường (không thưa thớt, các chỉ số bắt đầu giống như trong tất cả các shell khác nhưng ksh / bash), $*
được coi là một mảng bình thường. zsh
có $argv
một bí danh cho nó (để tương thích với csh
). $*
là giống như $argv
hoặc ${argv[*]}
(các đối số được nối với ký tự đầu tiên của $IFS
nhưng vẫn được tách ra trong ngữ cảnh danh sách). "$@"
thích "${argv[@]}"
hoặc "${*[@]}"}
trải qua quá trình xử lý đặc biệt theo phong cách Korn.