Это началось как взломать оболочку Борна. В оболочке 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.