Доступ к аргументам командной строки 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.