Це почалося як злом у оболонці Борна. У оболонці Борна було виконано розбиття слів 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[@]}"
або "${*[@]}"}
проходить спеціальну обробку в стилі Корн.