Đ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ừ forlặ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ừ, $varsẽ đượ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 edvới t, f, le.txt, f, le2.txtnhư 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 $1chứa foo barvà $2chứ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 $IFSmặ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 $IFSkhô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 $IFSkhô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ư
edithoặc file.txttrong ví dụ trên)
$*và $@được nối với ký tự đầu tiên của $IFShoặc khoảng $IFStrắ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 IFStrố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/ yashtrong đó $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 $IFSkhông chứa khoảng trắng trừ khi IFStrố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 $IFStrắ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.
bashCá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
$IFSthay 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 $IFStrố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 kshhoặc bashtrong đó:
- 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 zshhoặc yashnơ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. zshcó $argvmột bí danh cho nó (để tương thích với csh). $*là giống như $argvhoặc ${argv[*]}(các đối số được nối với ký tự đầu tiên của $IFSnhư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.