Хотя это кажется ошибкой, я сталкивался с некоторыми странными крайними случаями с "... $ @" и раньше, и это соответствует ожидаемому поведению, по крайней мере, исторически. " $@"
(с висячими пробелами) - неопределенное поведение , потому что вы в основном запрашиваете, чтобы все члены массива $@
рассматривались как аргументы для синтаксического анализатора оболочки плюс один символ пробел. Может быть немного сложно обернуть голову, и некоторые из вещей, которые вы сказали, вводят в заблуждение, поэтому я решил предоставить больше информации и советы для достижения лучшего поведения.
То, как вы используете "$ @" и пытаетесь заменить его на "$ *", может вызвать проблемы. Существуют значительные различия между поведением $*
и $@
, которое соответствует их предполагаемому использованию. Если вы используете $@
, это потому, что вы хотите сделать что-то вроде этого:
wrapper_fxn() {
wrapped_cmd "$@"
}
Когда вы заключаете $ @ в кавычки (и любой другой массив в этом отношении), bash оценивает его , как если бы каждый аргумент / член массива сначала был заключен в двойные кавычки. Тем не менее, здесь задействовано немного больше магии, так как он фактически не заключает в двойные кавычки, а удаляет двойные кавычки, но указывает на изменение поведения при разборе на более позднем этапе.
Причина, по которой существует специальное поведение "$@"
, заключается в том, чтобы помочь справиться с неприятными помехами quoting
& argv
.
Итак, думайте о них так:
- $ @: несколько аргументов / для распространения аргументов при сохранении цитирования пробела
- $ *: один аргумент / для объединения всех строк в массиве в один аргумент
Мой совет: не делай "$@ "
; это неопределенное поведение. Как только вы цитируете как "$@"
, вы пытаетесь выполнить расширение аргумента и добавить еще один аргумент или массив аргументов, просто сделайте это так:
# Making sure to have quotes around each new arg
somecmd "$newFirstArg" "$@" "${additionalArray[@]}" "$newLastArg"
... это лучше сообщит о намерениях и почти никогда не даст неожиданного поведения.
Подробнее
Учитывая все вышесказанное, странное поведение ребра "$ @" связано с тем, когда вы используете его, например: "... $@"
, как и "$ @". Bash объединит один из элементов массива в зависимости от позиции ...
с дополнительными символами.
Когда вы добавляете что-либо справа или слева от $@
в цитируемом утверждении, например "extra stuff $@"
или "$@ extra stuff"
, то, что сделает bash, это просто добавит extra stuff
в первый или последний член массива соответственно. Исключением является случай, когда в операторе с двойными кавычками есть другой массив, возможно, $@
, дублированный так: "$@ $@"
. Фактически он объединит последний элемент первого массива с первым элементом последнего массива. Таким образом, если в $@
есть три члена, в окончательном argv[]
из "$@ $@"
будет 5 аргументов, а не 6.
Вот полезная функция, помогающая разобраться в поведении:
# example function
print-args ()
{
local i=0;
for arg in "$@";
do
printf "[${i}]:%s\n" "\"$arg\"";
let i++;
done
}
# good example arg-set covering many of the important edge cases
set "one \"one" two three
# One case, modify it to see the various permutations of the edge cases
print-args " $@ $@ "
#>[0]:" one "one"
#>[1]:"two"
#>[2]:"three one "one"
#>[3]:"two"
#>[4]:"three "