Piszę bardzo prosty skrypt, który wywołuje inny skrypt, i muszę propagować parametry z bieżącego skryptu do skryptu, który wykonuję.
Na przykład moja nazwa skryptu to foo.sh
i wywołaniabar.sh
foo.sh:
bar $1 $2 $3 $4
Jak mogę to zrobić bez wyraźnego określenia każdego parametru?
bash
command-line-arguments
Fragsworth
źródło
źródło
Odpowiedzi:
Użyj
"$@"
zamiast zwykłego,$@
jeśli faktycznie chcesz, aby parametry były takie same.Przestrzegać:
źródło
'arg with spaces'
trzy przykłady. Byłem zaskoczony wynikami; mam nadzieję, że potrafisz je wyjaśnić../foo.sh "arg with spaces"
i./foo.sh 'arg with spaces'
są w 100% identyczne, więc nie rozumiem, w jaki sposób sugestia dodania go do podanych przykładów byłaby pomocna.W przypadku bash i innych powłok podobnych do Bourne'a:
źródło
$argv:q
zadziała w niektórych wariantach csh.exec java com.myserver.Program "$@"
Powoduje to, że bash wykona polecenie Java, zamiast czekać na zakończenie. Tak więc korzystasz z jednego mniejszego gniazda procesu. Ponadto, jeśli proces nadrzędny (który uruchomił skrypt) obserwuje go przez pid i oczekuje, że będzie to proces „java”, niektóre nietypowe rzeczy mogą się zepsuć, jeśli nie wykonasz exec; exec powoduje, że java dziedziczy ten sam pid.args=("$@")
i rozwiń każdy element jako osobne „słowo” powłoki ( pokrewny"$@"
) z"${args[@]}"
."$@"
, tak jak nie powiedzie się, jeśli spacja w argumencie, znaki zerowe lub inne znaki specjalne zawiodą?Użyj
"$@"
(działa dla wszystkich kompatybilnych z POSIX ).Z Bash przez przykład .
źródło
$*
. Wierzę, że tutaj jest historyczny postęp;$*
nie działał zgodnie z przeznaczeniem, dlatego$@
został wymyślony, aby go zastąpić; ale reguły cytowania są takie, jakie są, podwójne cytaty wokół niego są nadal wymagane (w przeciwnym razie nastąpi powrót do zepsutej$*
semantyki).echo "$@"
jako,./script.sh a "b c" d
to po prostu dostajesza b c d
zamiasta "b c" d
, co jest bardzo różne.echo
otrzymujemy trzy argumenty:"a" "b c" "d"
(wtedy powłoka łączy je razem w ramach rozszerzenia łańcucha). Ale gdybyś użyłfor i in "$@"; do echo $i; done
, dostałbyśa⏎b c⏎d
.Zdaję sobie sprawę, że dobrze na nie odpowiedziano, ale oto porównanie między „$ @” $ @ „$ *” i $ *
Zawartość skryptu testowego:
Teraz uruchom skrypt testowy z różnymi argumentami:
źródło
Pomyślałem, że może to być nieco bardziej przydatne podczas próby sprawdzenia, w jaki sposób argony wchodzą do twojego skryptu
źródło
$#
""
,''
jako argument, także jeśli nie było argumentów, milczy. Próbowałem to naprawić, ale potrzebuję pętli for i przeciwdziałam$#
. Właśnie dodałem to na końcu:echo "End of args or received quoted null"
Mój SUN Unix ma wiele ograniczeń, nawet „$ @” nie było interpretowane jako pożądane. Moje obejście to {@}. Na przykład,
Nawiasem mówiąc, musiałem mieć ten konkretny skrypt, ponieważ mój Unix również nie obsługuje grep -r
źródło
ksh
Jeśli uwzględnisz
$@
w cudzysłowie zostanie dołączony ciąg znaków, zachowanie jest bardzo dziwne, gdy występuje wiele argumentów, tylko pierwszy argument jest zawarty w cudzysłowie.Przykład:
Wydajność:
Ale najpierw przypisując inną zmienną:
Wydajność:
źródło
"$@"
bash. Pomaga również zilustrować kluczową różnicę między$@
i$*
, i dlaczego oba są przydatne. Ze strony podręcznikabash(1)
sekcja Parametry specjalne: „*
- Gdy rozwinięcie występuje w obrębie podwójnych cudzysłowów, rozwija się do pojedynczego słowa o wartości każdego parametru […] Oznacza to, że"$*"
jest równoważne"$1c$2c..."
, gdziec
jest [$IFS
].” I rzeczywiście, użycie$*
zamiast$@
w pierwszym przykładzie dałoby wynik netto identyczny jak w drugiej wersji."$@"
. Ponownie ze strony podręcznika: „@
- Gdy interpretacja występuje w obrębie podwójnych cudzysłowów, każdy parametr jest interpretowany jako osobne słowo. To znaczy"$@"
jest równoważne"$1"
"$2"
… Jeśli podwójny cudzysłów występuje w danym słowie, interpretacja pierwszego parametru jest łączona z początkową częścią oryginalnego słowa, a rozwinięcie ostatniego parametru jest połączone z ostatnią częścią oryginalnego słowa. ” ... I rzeczywiście, jeśli twój kod byłbash -c "true foo $@ bar baz"
, to uruchom go tak, jak wtest.sh one two
siecibash -c 'true foo one' 'two bar baz'
.$*
, wydaje mi się, że zapominam, że istnieje ..$@
zaczynałem zyskiwać na popularności, kiedy zacząłem pisać skrypty powłoki, wciąż muszę sobie przypominać, że tam jest. Często"$*"
używano ich w skryptach ... wtedy autor zdawał sobie sprawę, że rozbijał wszystkie ich argumenty, więc próbowali wszelkiego rodzaju złożonych bzdur z podziałem słów"$*"
lub [ponownie] składali listę argumentów przez zapętlanie ponadshift
ciągnąć je jeden po drugim ... tylko za pomocą$@
rozwiązuje go. (Pomaga temu bashowi używać również tego samego mnemonika, aby uzyskać dostęp do członków tablicy:${var[*]}
dla nich wszystkich jako słowa,${var[@]}
dla listy słów.)bash -c
w sposób, który nie ma absolutnie żadnego sensu.Czasami chcesz przekazać wszystkie argumenty, ale poprzedza je flaga (np.
--flag
)Możesz to zrobić w następujący sposób:
Uwaga: aby uniknąć dodatkowego podziału pola, musisz zacytować
%s
i$@
, aby uniknąć pojedynczego łańcucha, nie możesz zacytować podpowłokiprintf
.źródło
Działa dobrze, chyba że masz spacje lub znaki ucieczki. W tym przypadku nie znajduję sposobu na przechwycenie argumentów i wysłanie do ssh w skrypcie.
Może to być przydatne, ale jest tak brzydkie
źródło
Wiele odpowiedzi tutaj poleca
$@
lub$*
z cytatami i bez, jednak wydaje się, że żadna nie wyjaśnia, co one naprawdę robią i dlaczego powinieneś w ten sposób. Pozwól mi więc ukraść to doskonałe streszczenie z tej odpowiedzi :Zauważ, że cytaty mają znaczenie i bez nich oba mają identyczne zachowanie.
W moim celu musiałem przekazywać parametry z jednego skryptu do drugiego w obecnej postaci, a najlepszą opcją jest:
Zauważ, że nie ma cytatów i
$@
powinien również działać w powyższej sytuacji.źródło
bar "$@"
będzie równoważne zbar "$1" "$2" "$3" "$4"
Zauważ, że znaki cudzysłowu są ważne!
"$@"
,$@
,"$*"
Lub$*
każdy będzie zachowywać się nieco inaczej w sprawie ucieczki i łączenie w sposób opisany w niniejszym stackoverflow odpowiedź .Jednym ściśle powiązanym przypadkiem użycia jest przekazanie wszystkich podanych argumentów w argumencie takim jak ten:
bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\""
.Używam odmiany odpowiedzi @ kvantour, aby to osiągnąć:
bash -c "bar $(printf -- '"%s" ' "$@")"
źródło