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