Wybór nalezy do ciebie. Jeśli nie podasz $@
żadnej z jej wartości, poddaj ją dodatkowej rozbudowie i interpretacji. Jeśli ją zacytujesz, wszystkie przekazane argumenty są odtwarzane dosłownie w jej rozwinięciu. Nigdy nie będziesz w stanie w niezawodny sposób obsługiwać tokenów składni powłoki, takich jak &>|
i etc, bez samodzielnego analizowania argumentów - więc masz bardziej rozsądny wybór przekazania funkcji:
- Dokładnie słowa użyte w wykonaniu pojedynczego prostego polecenia za pomocą
"$@"
.
...lub...
- Kolejna rozszerzona i zinterpretowana wersja twoich argumentów, które są następnie stosowane razem jako proste polecenie z
$@
.
Żaden sposób nie jest zły, jeśli jest celowy i jeśli skutki tego, co wybierzesz, są dobrze zrozumiane. Oba sposoby mają zalety jeden nad drugim, chociaż zalety drugiego rzadko są szczególnie przydatne. Nadal...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... to nie ma sensu , tylko rzadko mogą być znacznie użytku . A w bash
powłoce, ponieważ bash
domyślnie nie przykleja definicji środowiska do swojego środowiska, nawet jeśli wspomniana definicja jest dołączona do wiersza polecenia specjalnego wbudowanego lub funkcji, globalna wartość parametru $IFS
nie jest zmieniana, a deklaracja jest lokalna tylko na run_this()
połączenie.
Podobnie:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... globbing jest również konfigurowalny. Cytaty służą celowi - nie są na darmo. Bez nich rozszerzenie powłoki podlega dodatkowej interpretacji - interpretacji konfigurowalnej . Kiedyś - z kilkoma bardzo starymi powłokami - $IFS
był globalnie stosowany do wszystkich danych wejściowych, a nie tylko rozszerzeń. W rzeczywistości wspomniane powłoki zachowywały się bardzo podobnie run_this()
, ponieważ łamały wszystkie słowa wejściowe o wartości $IFS
. Tak więc, jeśli szukasz tego bardzo starego zachowania powłoki, powinieneś użyć run_this()
.
Nie szukam tego i jestem w tej chwili dość mocno zmuszony, aby wymyślić przydatny przykład. Generalnie wolę, aby polecenia, które uruchamia moja powłoka, były tymi, które wpisuję. I tak, biorąc pod uwagę wybór, prawie zawsze run_that()
. Oprócz tego...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
Cokolwiek można cytować. Polecenia będą działać w cudzysłowie Działa, ponieważ do czasu uruchomienia polecenia wszystkie słowa wejściowe przeszły już usuwanie cudzysłowów - co jest ostatnim etapem procesu interpretacji danych wejściowych powłoki. Tak więc różnica między 'ls'
i ls
może mieć znaczenie tylko podczas interpretacji powłoki - i dlatego cytowanie ls
zapewnia, że żaden z nazwanych aliasówls
nie zostanie zastąpiony moim cytowanym ls
słowem polecenia. Poza tym jedyne, na co wpływają cytaty, to delimitacja słów (czyli jak i dlaczego działa cytowanie zmiennych / białych znaków) oraz interpretacja metaznaków i słów zastrzeżonych.
Więc:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Nigdy nie będziesz w stanie tego zrobić za pomocą ani, run_this()
ani run_that()
.
Ale nazwy funkcji, $PATH
polecenia „d” lub wbudowane funkcje wykonają dokładnie cytowane lub niecytowane, i właśnie tak działa run_this()
i run_that()
przede wszystkim działa. Z $<>|&(){}
żadną z nich nie będziesz w stanie nic zrobić . Krótko mówiąc eval
, jest.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Ale bez niego jesteś ograniczony limitami prostego polecenia na podstawie używanych cytatów (nawet jeśli nie, ponieważ $@
zachowuje się jak cytat na początku procesu, gdy polecenie jest analizowane dla metaznaków) . To samo ograniczenie dotyczy przypisań i przekierowań wiersza poleceń, które są ograniczone do wiersza polecenia funkcji. Ale to nie jest wielka sprawa:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
Mogłem mieć tak łatwo <
przekierowane wejście lub >
wyjście, jak otworzyłem potok.
W każdym bądź razie, nie ma tu dobrego ani złego sposobu - każdy sposób ma swoje zastosowanie. Po prostu powinieneś napisać to tak, jak zamierzasz go używać i powinieneś wiedzieć, co masz zamiar zrobić. Pomijając cytaty mogą mieć cel - w przeciwnym razie nie byłoby być cytaty w ogóle - ale jeśli pominąć ich istotnych powodów nie do celu, jesteś po prostu pisząc zły kod. Rób, co masz na myśli; W każdym razie staram się.
run_that
Zachowanie jest zdecydowanie tym, czego bym się spodziewał (a jeśli na ścieżce do polecenia będzie miejsce?). Jeśli chciałbyś innego zachowania, z pewnością wycofałbyś je z serwisu połączeń, na którym wiesz, jakie są dane? Spodziewałbym się wywołać tę funkcję jakorun_that ls -l
, która działa tak samo w obu wersjach. Czy jest przypadek, który sprawił, że spodziewałeś się inaczej?