tl; dr
Podeszwa stuff
będzie najprawdopodobniej pracować dla Ciebie.
Pełna odpowiedź
Co się dzieje
Kiedy biegniesz foo $(stuff)
, dzieje się tak:
stuff
biegnie;
- jego wyjście (standardowe wyjście), zamiast być drukowane, zastępuje
$(stuff)
wywołanie foo
;
- następnie
foo
uruchamia się, argumenty wiersza poleceń oczywiście zależą od tego, co zostało stuff
zwrócone.
Ten $(…)
mechanizm nazywa się „zastępowaniem poleceń”. W twoim przypadku głównym poleceniem jest echo
zasadniczo wypisywanie argumentów wiersza poleceń na standardowe wyjście. Wszystko, co stuff
próbuje wydrukować na standardowe wyjście, jest przechwytywane, przekazywane echo
i drukowane na standardowe wyjście echo
.
Jeśli chcesz, aby wyjście stuff
zostało wydrukowane na standardowe wyjście, po prostu uruchom podeszwę stuff
.
`…`
Składnia służy temu samemu celowi co $(…)
(pod tym samym tytułem: „podstawienia polecenia”), istnieje kilka różnic chociaż, więc nie można ślepo je wymieniać. Zobacz to FAQ i to pytanie .
Czy powinienem unikać echo $(stuff)
bez względu na wszystko?
Istnieje powód, z którego możesz skorzystać, echo $(stuff)
jeśli wiesz, co robisz. Z tego samego powodu powinieneś unikać, echo $(stuff)
jeśli tak naprawdę nie wiesz, co robisz.
Chodzi o to stuff
i echo $(stuff)
nie jest dokładnie równoważne. Ten ostatni oznacza wywołanie operatora split + glob na wyjściu stuff
z wartością domyślną $IFS
. Podwójne cytowanie podstawienia polecenia zapobiega temu. Cytując pojedynczą zamianę polecenia, nie jest to już podstawienie polecenia.
Aby to zaobserwować, jeśli chodzi o dzielenie, uruchom następujące polecenia:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
I do globowania:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Jak widać, echo "$(stuff)"
jest to odpowiednik (-ish *) stuff
. Możesz go użyć, ale po co komplikować to w ten sposób?
Z drugiej strony, jeśli chcesz wyjście stuff
do poddania dzielenie + uogólniające wtedy mogą znaleźć echo $(stuff)
przydatne. To jednak musi być twoja świadoma decyzja.
Istnieją polecenia generujące dane wyjściowe, które powinny zostać ocenione (w tym dzielenie, globowanie i inne) i uruchamiane przez powłokę, więc eval "$(stuff)"
jest taka możliwość (patrz ta odpowiedź ). Nigdy nie widziałem polecenia, które wymagałoby wyjścia w celu dodatkowego podziału + globowania przed wydrukowaniem . Celowe używanie echo $(stuff)
wydaje się bardzo rzadkie.
Co var=$(stuff); echo "$var"
?
Słuszna uwaga. Ten fragment kodu:
var=$(stuff)
echo "$var"
powinno być równoważne z echo "$(stuff)"
(-ish *) do stuff
. Jeśli jest to cały kod, po prostu uruchom stuff
zamiast tego.
Jeśli jednak musisz użyć wyników stuff
więcej niż jeden raz, to podejście
var=$(stuff)
foo "$var"
bar "$var"
jest zwykle lepszy niż
foo "$(stuff)"
bar "$(stuff)"
Nawet jeśli foo
tak, echo
i dostaniesz echo "$var"
kod, może być lepiej zachować go w ten sposób. Rzeczy do rozważenia:
- Z
var=$(stuff)
stuff
biegami raz; nawet jeśli polecenie jest szybkie, właściwym rozwiązaniem jest unikanie dwukrotnego obliczania tego samego wyniku. A może stuff
ma skutki inne niż pisanie na standardowe wyjście (np. Tworzenie pliku tymczasowego, uruchamianie usługi, uruchamianie maszyny wirtualnej, powiadamianie zdalnego serwera), więc nie chcesz uruchamiać go wiele razy.
- Jeśli
stuff
generuje czasu w zależności czy wyjście nieco przypadkowy, można uzyskać niespójne wyniki foo "$(stuff)"
i bar "$(stuff)"
. Po var=$(stuff)
ustaleniu wartości $var
i możesz być pewny foo "$var"
i bar "$var"
uzyskać identyczny argument wiersza poleceń.
W niektórych przypadkach zamiast tego foo "$var"
możesz chcieć (potrzebować) użyć foo $var
, szczególnie jeśli stuff
generuje wiele argumentów dla foo
(zmienna tablicowa może być lepsza, jeśli twoja powłoka ją obsługuje). Znowu wiedz, co robisz. Jeśli chodzi o echo
różnicę między echo $var
i echo "$var"
jest taka sama jak między echo $(stuff)
i echo "$(stuff)"
.
* Odpowiednik ( -ish )?
Powiedziałem, że echo "$(stuff)"
jest równoważne (-ish) do stuff
. Istnieją co najmniej dwa problemy, które sprawiają, że nie jest to dokładnie równoważne:
$(stuff)
działa stuff
w podpowłoce, więc lepiej powiedzieć, że echo "$(stuff)"
jest równoważne (-ish) (stuff)
. Polecenia, które wpływają na powłokę, w której działają, jeśli są w podpowłoce, nie wpływają na główną powłokę.
W tym przykładzie stuff
jest a=1; echo "$a"
:
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Porównaj to z
a=0
a=1; echo "$a" # stuff
echo "$a"
i z
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Kolejny przykład, zacznij od stuff
bycia cd /; pwd
:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
oraz testy stuff
i (stuff)
wersje.
echo
nie jest dobrym narzędziem do wyświetlania niekontrolowanych danych . To, o echo "$var"
czym rozmawialiśmy, powinno być printf '%s\n' "$var"
. Ale ponieważ wspomniano w tym pytaniu echo
i ponieważ najbardziej prawdopodobnym rozwiązaniem nie jest zastosowanie echo
w pierwszej kolejności, postanowiłem nie przedstawiać printf
do tej pory.
stuff
lub (stuff)
przeplata wyjście stdout i stderr, jednocześnie echo $(stuff)
wypisując wszystkie wyjście stderr z stuff
(które uruchamia się jako pierwsze), a dopiero potem przetworzone wyjście stdout przez echo
(które uruchamia się jako ostatnie).
$(…)
usuwa wszelkie końcowe znaki nowej linii, a następnie echo
dodaje je z powrotem. echo "$(printf %s 'a')" | xxd
Daje więc inną wydajność niż printf %s 'a' | xxd
.
Niektóre polecenia ( ls
na przykład) działają inaczej w zależności od tego, czy standardowym wyjściem jest konsola, czy nie; to ls | cat
samo nie ls
robi. Podobnie echo $(ls)
będzie działać inaczej niż ls
.
Odkładając na ls
bok, w ogólnym przypadku, jeśli musisz zmusić to inne zachowanie, to stuff | cat
jest lepsze niż echo $(ls)
lub echo "$(ls)"
ponieważ nie powoduje to wszystkich innych problemów wymienionych tutaj.
Prawdopodobnie inny status wyjścia (wspomniany dla kompletności tej odpowiedzi na wiki; szczegółowe informacje znajdują się w innej odpowiedzi, która zasługuje na uznanie).