Доступ к аргументам командной строки bash $ @ vs $ *


327

Во многих вопросах и руководствах по bash я вижу, что могу получить доступ к аргументам командной строки в сценариях bash двумя способами:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

Что приводит к:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

В чем разница между $*и $@?
Когда следует использовать первое и когда использовать второе?


взгляните на этот ответ: stackoverflow.com/a/842325/671366
кодирование

статический анализ в IntelliJ трактует echo "something $@"как ошибку
Алекс Кон

Ответы:


437

Разница появляется, когда указаны специальные параметры. Позвольте мне проиллюстрировать различия:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

Еще один пример важности цитирования: обратите внимание, что между «arg» и числом есть 2 пробела, но если я не смогу процитировать $ word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

и в bash, "$@"это список "по умолчанию" для перебора:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3

65
+1 Я всегда думал, что эту концепцию лучше всего продемонстрировать на простом примере, в котором полностью отсутствует руководство по bash.
Чепнер

5
Есть ли возможный вариант использования, когда $*или "$*"может потребоваться, и цель не может быть достигнута $@или "$@"?
anishsane

5
Какая версия больше подходит для скрипта-обёртки, где параметры скрипта должны стать параметрами новой команды?
Segfault

7
@Segfault, в этом случае, всегда выбирайте "$@"с кавычками.
Гленн Джекман

2
Этот ответ содержит полезные примеры, но было бы лучше, если бы он также объяснил механизм, стоящий за ними. Почему это работает так?
Лий

255

Хорошая удобная обзорная таблица из Bash Hackers Wiki :

$ * против $ @ таблицы

где cв третьем ряду находится первый символ $IFS, Разделитель внутренних полей, переменная оболочки.

Если аргументы должны храниться в переменной скрипта, а аргументы должны содержать пробелы, я искренне рекомендую использовать "$*"трюк с внутренним разделителем полей, $IFSустановленным на tab .


42
... где "c" - первый символ $ IFS
Гленн Джекман

39
... и $IFSрасшифровывается как «Внутренний разделитель полей».
Серж Строобандт

Вот пример , который включает ввод в кавычки. Вход также имеет значение!
Серж

Допустим, я хочу создать скрипт-обертку, который не имитирует ничего, кроме функции упакованной команды. Какой синтаксис я должен использовать для передачи аргументов из сценария оболочки во внутреннюю команду?
Маринос Ан

44

$ *

Расширяется до позиционных параметров, начиная с единицы. Когда раскрытие происходит в двойных кавычках, оно расширяется до одного слова со значением каждого параметра, разделенным первым символом специальной переменной IFS. То есть «$ *» эквивалентно «$ 1c $ 2c ...», где c - первый символ значения переменной IFS. Если IFS не установлен, параметры разделяются пробелами. Если IFS равен нулю, параметры объединяются без промежуточных разделителей.

$ @

Расширяется до позиционных параметров, начиная с единицы. Когда раскрытие происходит в двойных кавычках, каждый параметр раскрывается в отдельное слово. То есть "$ @" эквивалентно "$ 1" "$ 2" ... Если раскрытие в двойных кавычках происходит внутри слова, расширение первого параметра объединяется с начальной частью исходного слова и расширением последнего параметра объединяется с последней частью исходного слова. Когда позиционные параметры отсутствуют, $ @ и $ @ расширяются до нуля (то есть они удаляются).

Источник: Баш человек


15

$ @ совпадает с $ *, но каждый параметр является строкой в ​​кавычках, то есть параметры передаются без изменений, без интерпретации или расширения. Это означает, среди прочего, что каждый параметр в списке аргументов рассматривается как отдельное слово.

Конечно, "$ @" следует заключать в кавычки.

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST


1

Этот пример let может выделить разницу между «at» и «asterix», когда мы их используем. Я объявил два массива "фрукты" и "овощи"

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

Смотрите следующий результат, код выше:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion

7
С научной точки зрения помидоры - это фрукты.
Рэнди

1
Вы имеете право! «В ботанике плод - это семенная структура у цветковых растений (также называемых покрытосеменными), образующаяся из яичника после цветения». ru.wikipedia.org/wiki/Fruit
stefansson

@Randy: с научной точки зрения все фрукты - это овощи (это синоним "растения").
Крис Луенго

@CrisLuengo ересь! :)
Рэнди
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.