Це почалося як злом у оболонці Борна. У оболонці Борна було виконано розбиття слів IFS (після маркірування) на всі слова в контексті списку (аргументи командного рядка або слова, що forцикли циклічно включені ). Якщо у вас були:
IFS=i var=file2.txt
edit file.txt $var
Це друга лінія буде tokenised в 3 -х слів, $varбуде розширено, і розкол + Glob буде зроблено на всіх трьох слів, так що ви в кінцевому підсумку працює edз t, f, le.txt, f, в le2.txtякості аргументів.
Цитування частин цього завадить запобігти спліт + glob. Оболонка Борна спочатку запам'ятала, які символи були цитовані, встановивши 8-й біт на них внутрішньо (що змінилося пізніше, коли Unix став 8-бітовим чистим, але оболонка все-таки зробила щось подібне, щоб запам'ятати, який байт був цитований).
І те $*й $@інше було об'єднанням позиційних параметрів з проміжком між ними. Але була спеціальна обробка, $@коли всередині подвійних лапок. Якщо вони $1містяться foo barі $2містяться baz, "$@"вони розширяться до:
foo bar baz
^^^^^^^ ^^^
(з ^s вище вказуючи, який із символів має 8-й біт). Там, де було вказано перший пробіл (було встановлено восьмий біт), але не другий (той додав проміжні слова).
І розділення аргументів здійснює розбиття IFS (якщо припустимо, що пробіл символу є $IFSтаким, яким він є за замовчуванням). Це схоже на те, як $*було розширено у попередника оболонки Маші (сама на основі оболонки Томсона, тоді як оболонка Борна була написана з нуля).
Це пояснює, чому в оболонці Bourne спочатку "$@"було б розширитись до порожнього рядка замість нічого взагалі нічого, коли список позиційних параметрів був порожнім (вам довелося обходити його ${1+"$@"}), чому він не зберігав порожні позиційні параметри і чому "$@"не не працювати, коли $IFSне містив символу пробілу.
Намір мав змогу передати аргумент дослівно до іншої команди, але це не спрацювало належним чином для порожнього списку, для порожніх елементів або коли $IFSне містило місця (перші два питання врешті-решт були виправлені в пізніших версіях ).
Оболонка Korn (на якій базується специфікація POSIX) змінила таку поведінку кількома способами:
- Розбиття IFS проводиться лише в результаті розширень без котирування (не на буквальних словах, таких як
editабо file.txtу наведеному вище прикладі)
$*і $@з'єднуються з першим символом $IFSабо пробілом, коли $IFSпорожній, за винятком котируваного "$@", цей столяр не котирується , як у оболонці Борна, а для котирується, "$*"коли IFSпорожній, позиційні параметри додаються без роздільника.
- вона була додана підтримка масивів, і
${array[@]} ${array[*]}нагадує Борна $*і $@але починаючи з Indice 0 замість 1, і рідкісними (більше як асоціативні масиви) , що означає на $@насправді не можна розглядати як масив КШ (порівняйте з csh/ rc/ zsh/ fish/ , yashде $argv/ $*нормальні масиви).
- Порожні елементи збереглися.
"$@"коли $#0 зараз розширюється до нічого замість порожнього рядка, "$@"працює, коли $IFSне містить пробілів, крім випадків, коли IFSпорожній. $*Без котировки без підстановок розширюється один аргумент (де позиційні параметри з'єднані з пробілом), коли $IFSпорожній.
ksh93 виправив решту кількох проблем вище. У ksh93, $*і $@розширюється до списку позиційних параметрів, відокремлюється незалежно від значення $IFS, а потім подальше розділення + globbed + brace-розширене у контекстах списку, $*об'єднане з першим байтом (не символом) $IFS, "$@"у списку контексти розширюється до списку позиційних параметрів, незалежно від значення $IFS. У контексті, що не є списком, як і в var=$@, $@з'єднується з простором незалежно від значення $IFS.
bashмасиви 's проектуються після ksh. Відмінності:
- відсутність дужок-розгортань при розширенні без котирування
- перший символ
$IFSзамість байта
- деякі кутові відмінності, такі як розширення,
$*коли не котирується в контексті, що не є списком, коли $IFSвоно порожнє.
Хоча специфіка POSIX раніше була досить розпливчастою, вона тепер більш-менш визначає поведінку баш.
Це відрізняється від звичайних масивів у тому kshчи іншому bash:
- Індекси починаються з 1 замість 0 (за винятком того,
"${@:0}"що включає $0(не позиційний параметр, а у функціях дає назву функції чи не залежно від оболонки та того, як функція була визначена)).
- Ви не можете призначати елементи окремо
- це не рідко, ви не можете знімати елементи окремо
shift може бути використаний.
У zshабо yashтам, де масиви є нормальними масивами (не розрідженими, індекси починаються з одного, як у всіх інших оболонках, але ksh / bash), $*трактується як звичайний масив. zshмає $argvпсевдонім для нього (для сумісності з csh). $*- це те саме, що $argvабо ${argv[*]}(аргументи, об'єднані з першим символом, $IFSале все ще відокремлені в контекстах списку). "$@"подобається "${argv[@]}"або "${*[@]}"}проходить спеціальну обробку в стилі Корн.