Krótka odpowiedź: użyj"$@"
(zwróć uwagę na podwójne cudzysłowy). Inne formy są bardzo rzadko przydatne.
"$@"
jest raczej dziwną składnią. Jest on zastępowany przez wszystkie parametry pozycyjne, jako osobne pola. Jeśli nie ma parametrów pozycyjnych ( $#
wynosi 0), wówczas "$@"
rozwija się do zera (nie jest to pusty ciąg, ale lista z 0 elementami), jeśli istnieje jeden parametr pozycyjny, to "$@"
jest równoważny "$1"
, jeśli są dwa parametry pozycyjne, to "$@"
jest równoważny z "$1" "$2"
itd.
"$@"
pozwala przekazać argumenty skryptu lub funkcji do innego polecenia. Jest to bardzo przydatne w przypadku opakowań, które wykonują takie czynności, jak ustawianie zmiennych środowiskowych, przygotowywanie plików danych itp. Przed wywołaniem polecenia z tymi samymi argumentami i opcjami, które zostały wywołane przez opakowanie.
Na przykład poniższa funkcja filtruje dane wyjściowe cvs -nq update
. Oprócz filtrowania danych wyjściowych i statusu zwracanego (który ma grep
raczej status niż zamiast cvs
), wywoływanie cvssm
niektórych argumentów zachowuje się jak wywoływanie cvs -nq update
z tymi argumentami.
cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }
"$@"
rozwija się do listy parametrów pozycyjnych. W powłokach obsługujących tablice istnieje podobna składnia, aby rozwinąć listę elementów tablicy: "${array[@]}"
(nawiasy klamrowe są obowiązkowe oprócz zsh). Ponownie, podwójne cudzysłowy są nieco mylące: chronią przed podziałem pola i generowaniem wzorca elementów tablicy, ale każdy element tablicy kończy się na swoim własnym polu.
Niektóre starożytne powłoki miały coś, co jest prawdopodobnie błędem: gdy nie było argumentów pozycyjnych, "$@"
rozszerzono je do pojedynczego pola zawierającego pusty ciąg, zamiast do żadnego pola. Doprowadziło to do obejścia${1+"$@"}
( rozsławionego za pomocą dokumentacji Perla ). Wpływa to tylko na starsze wersje rzeczywistej powłoki Bourne'a i implementacji OSF1, a żadna z jej nowoczesnych kompatybilnych zamienników (ash, ksh, bash,…) nie jest zagrożona. /bin/sh
nie ma wpływu na żaden system, który został wydany w XXI wieku, o którym wiem (chyba że policzysz wersję aktualizacyjną Tru64, a nawet /usr/xpg4/bin/sh
jest bezpieczny, więc #!/bin/sh
dotyczy to tylko skryptu, a nie #!/usr/bin/env sh
skryptów, o ile twoja ŚCIEŻKA jest skonfigurowana pod kątem zgodności z POSIX) . Krótko mówiąc, jest to historyczna anegdota, o którą nie musisz się martwić.
"$*"
zawsze rozwija się do jednego słowa. To słowo zawiera parametry pozycyjne, połączone ze spacją pomiędzy nimi. (Mówiąc bardziej ogólnie, separator jest pierwszym znakiem wartości IFS
zmiennej. Jeśli wartość IFS
jest pustym łańcuchem, separator jest pustym łańcuchem.) Jeśli nie ma parametrów pozycyjnych, to "$*"
jest to pusty ciąg, jeśli są dwa parametry pozycyjne, a IFS
ich wartość domyślna "$*"
jest wówczas równoważna "$1 $2"
itp.
$@
a $*
cytaty zewnętrzne są równoważne. Rozwijają się do listy parametrów pozycyjnych, jako oddzielne pola, takie jak "$@"
; ale każde wynikowe pole jest następnie dzielone na osobne pola, które są traktowane jak wzorce symboli wieloznacznych nazw plików, jak zwykle z niecytowanymi rozszerzeniami zmiennych.
Na przykład jeśli bieżący katalog zawiera trzy pliki bar
, baz
a foo
następnie:
set -- # no positional parameters
for x in "$@"; do echo "$x"; done # prints nothing
for x in "$*"; do echo "$x"; done # prints 1 empty line
for x in $*; do echo "$x"; done # prints nothing
set -- "b* c*" "qux"
echo "$@" # prints `b* c* qux`
echo "$*" # prints `b* c* qux`
echo $* # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`