Dostęp do wiersza poleceń bash $ @ vs $ *


327

W wielu pytaniach SO i samouczkach bash widzę, że mogę uzyskać dostęp do argumentów wiersza poleceń w skryptach bash na dwa sposoby:

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

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

Co skutkuje w:

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

Jaka jest różnica między $*i $@?
Kiedy należy użyć tego pierwszego, a kiedy drugiego?


spójrz na tę odpowiedź: stackoverflow.com/a/842325/671366
— kodowanie

analiza statyczna w IntelliJ traktuje echo "something $@"jako błąd
— Alex Cohn

Odpowiedzi:


436

Różnica pojawia się, gdy podane są parametry specjalne. Pozwól mi zilustrować różnice:

$ 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

jeszcze jeden przykład na znaczenie cytowania: zwróć uwagę, że pomiędzy „arg” a liczbą są 2 spacje, ale jeśli nie podam słowa $:

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

a w bash "$@"jest „domyślną” listą do iteracji:

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

65
+1 Zawsze myślałem, że tę koncepcję najlepiej demonstruje prosty przykład, w którym całkowicie brakuje instrukcji bash.
— chepner

5
Czy istnieje możliwy przypadek użycia, kiedy $*lub "$*"może być wymagany, a cel nie może być obsługiwany przez $@lub "$@"?
— anishsane

5
Która wersja jest bardziej odpowiednia dla skryptu „otoki”, w którym parametry skryptów muszą stać się parametrami nowego polecenia?
— Segfault

7
@ Segfault, w tym przypadku, zawsze wybieraj "$@"z cudzysłowami.
— glenn jackman

2
Ta odpowiedź zawiera użyteczne przykłady, ale lepiej byłoby, gdyby wyjaśniła także mechanizm za nimi. Dlaczego tak to działa?
— Lii

255

Niezła poręczna tabela przeglądowa z Wiki Bash Hackers :

$ * w porównaniu do $ @ table

gdzie cw trzecim rzędzie znajduje się pierwszy znak $IFS, Separator pól wewnętrznych, zmienna powłoki.

Jeśli argumenty mają być przechowywane w zmiennej skryptu, a argumenty mają zawierać spacje, z całego serca polecam zastosowanie "$*"lewy z wewnętrznym separatorem pól $IFSustawionym na tab .


42
... gdzie „c” jest pierwszą postacią $ IFS
— glenn jackman

39
... i $IFSoznacza „Internal Field Separator”.
— Serge Stroobandt,

Oto przykład , który zawiera cytowane dane wejściowe. Ważny jest również wkład!
— Serge Stroobandt

Powiedzmy, że chcę utworzyć skrypt opakowujący, który naśladuje funkcjonalność zawiniętego polecenia. Jakiej składni należy użyć, aby przekazać argumenty ze skryptu opakowania do komendy wewnętrznej?
— Marinos An

44

$ *

Rozwija się do parametrów pozycyjnych, zaczynając od jednego. Kiedy rozwinięcie występuje w obrębie podwójnych cudzysłowów, rozwija się do pojedynczego słowa z wartością każdego parametru oddzieloną pierwszym znakiem zmiennej specjalnej IFS. Oznacza to, że „$ *” jest równoważne „$ 1c $ 2c ...”, gdzie c jest pierwszym znakiem wartości zmiennej IFS. Jeśli IFS jest rozbrojony, parametry są oddzielane spacjami. Jeśli IFS ma wartość NULL, parametry są łączone bez interwencji separatorów.

$ @

Rozwija się do parametrów pozycyjnych, zaczynając od jednego. Kiedy rozwinięcie występuje w podwójnych cudzysłowach, każdy parametr rozwija się do osobnego słowa. Oznacza to, że „$ @” jest równoważne z „$ 1” „$ 2” ... Jeśli podwójne wyrażenie występuje w jednym słowie, rozszerzenie pierwszego parametru jest łączone z początkową częścią oryginalnego słowa i rozwinięciem ostatniego parametru jest łączony z ostatnią częścią oryginalnego słowa. Gdy nie ma parametrów pozycyjnych, „$ @” i $ @ rozwijają się do zera (tzn. Są usuwane).

Źródło: Bash man


15

$ @ jest takie samo jak $ *, ale każdy parametr jest łańcuchem cytowanym, to znaczy parametry są przekazywane w stanie nienaruszonym, bez interpretacji lub interpretacji. Oznacza to między innymi, że każdy parametr na liście argumentów jest postrzegany jako osobne słowo.

Oczywiście należy podać „$ @”.

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


1

Ten przykład pozwala wyróżnić różnice między „at” i „asterix” podczas ich używania. Zadeklarowałem dwie tablice „owoce” i „warzywa”

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[@]}"    

Zobacz następujący wynik powyższy kod:

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
Z naukowego punktu widzenia pomidory to owoce.
— Randy

1
Masz racje! „W botanice owoc jest strukturą niosącą nasiona w roślinach kwiatowych (znanych również jako okrytozalążkowe) powstających z jajnika po kwitnieniu”. en.wikipedia.org/wiki/Fruit
— stefansson

@Randy: naukowo rzecz biorąc, wszystkie owoce są warzywami (to synonim nazwy „roślina”).
— Cris Luengo

@CrisLuengo herezja! :)
— Randy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.