Доступ до аргументів командного рядка bash $ @ vs $ *


327

У багатьох питаннях та навчальних посібниках бачу, що я можу отримати доступ до аргументів командного рядка в скриптах 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
codeling

статичний аналіз в IntelliJ трактує echo "something $@"як помилку
Алекс Кон

Відповіді:


436

Різниця з’являється при цитуванні спеціальних параметрів. Дозвольте проілюструвати відмінності:

$ 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" та числом є два пробіли, але якщо я не можу процитувати $ 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 Я завжди вважав, що цю концепцію найкраще продемонструє простий приклад, у якому посібника з башма повністю бракує.
чепнер

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

5
Яка версія більше підходить для сценарію "обгортки", де параметри сценаріїв повинні стати параметрами для нової команди?
Segfault

7
@Segfault, у цьому випадку завжди вибирайте "$@"цитати.
Глен Джекман

2
Ця відповідь містить корисні приклади, але було б краще, якби вона також пояснила механізм, що їх лежить. Чому це працює так?
Лій

255

Приємна зручна оглядова таблиця з Вікі Bash Hackers :

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

де cв третьому ряду - перший символ $IFS, роздільник внутрішнього поля, змінна оболонки.

Якщо аргументи мають бути збережені у змінній скрипту, і очікується, що аргументи містять пробіли, я від усієї душі рекомендую використовувати "$*"трюк із внутрішнім роздільником поля, $IFSвстановленим на вкладку .


42
... де "c" є першим персонажем $ IFS
glenn jackman

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

Ось приклад , який включає в себе цитовані матеріали. Вхід також має значення!
Серж Стробандт

Скажімо, я хочу створити скрипт для обгортки, який нічого не робить, але імітує функціональність загорнутої команди. Який синтаксис я повинен використовувати, щоб передати аргументи із сценарію обгортки до внутрішньої команди?
Марінос

44

$ *

Розширюється на позиційні параметри, починаючи з одиниці. Коли розширення відбувається в межах подвійних лапок, воно розширюється до одного слова зі значенням кожного параметра, розділеним першим символом спеціальної змінної IFS. Тобто, "$ *" еквівалентно "$ 1c $ 2c ...", де c - перший символ значення змінної IFS. Якщо IFS не встановлено, параметри розділяються пробілами. Якщо IFS недійсний, параметри з'єднуються без втручання роздільників.

$ @

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

Джерело: Баш людина


15

$ @ те саме, що $ *, але кожен параметр - це кодований рядок, тобто параметри передаються неушкодженими, без інтерпретації чи розширення. Це означає, серед іншого, що кожен параметр у списку аргументів розглядається як окреме слово.

Звичайно, "$ @" слід цитувати.

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


1

Цей приклад нехай може висвітлити відмінності між "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

6
Науково кажучи, томати - це фрукти.
Ренді

1
Ви маєте право! "У ботаніці плід - це насіннєва структура в квітучих рослинах (також відомих як покритонасінні), що утворюються з зав’язі після цвітіння". en.wikipedia.org/wiki/Fruit
stefansson

@Randy: науково кажучи, всі фрукти - це овочі (це синонім «рослина»).
Кріс Луенго

@ Єресь КрисЛуенго! :)
Ренді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.