tl; dr
Podeszwa stuffbę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
foouruchamia się, argumenty wiersza poleceń oczywiście zależą od tego, co zostało stuffzwrócone.
Ten $(…)mechanizm nazywa się „zastępowaniem poleceń”. W twoim przypadku głównym poleceniem jest echozasadniczo wypisywanie argumentów wiersza poleceń na standardowe wyjście. Wszystko, co stuffpróbuje wydrukować na standardowe wyjście, jest przechwytywane, przekazywane echoi drukowane na standardowe wyjście echo.
Jeśli chcesz, aby wyjście stuffzostał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 stuffi echo $(stuff)nie jest dokładnie równoważne. Ten ostatni oznacza wywołanie operatora split + glob na wyjściu stuffz 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 stuffdo 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 stuffzamiast tego.
Jeśli jednak musisz użyć wyników stuffwięcej niż jeden raz, to podejście
var=$(stuff)
foo "$var"
bar "$var"
jest zwykle lepszy niż
foo "$(stuff)"
bar "$(stuff)"
Nawet jeśli footak, echoi dostaniesz echo "$var"kod, może być lepiej zachować go w ten sposób. Rzeczy do rozważenia:
- Z
var=$(stuff) stuffbiegami raz; nawet jeśli polecenie jest szybkie, właściwym rozwiązaniem jest unikanie dwukrotnego obliczania tego samego wyniku. A może stuffma 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
stuffgeneruje 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 $vari 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 stuffgeneruje 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 echoróżnicę między echo $vari 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 stuffw 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 stuffjest 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 stuffbycia cd /; pwd:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
oraz testy stuffi (stuff)wersje.
echonie 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 echoi ponieważ najbardziej prawdopodobnym rozwiązaniem nie jest zastosowanie echow pierwszej kolejności, postanowiłem nie przedstawiać printfdo tej pory.
stufflub (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 echododaje je z powrotem. echo "$(printf %s 'a')" | xxdDaje więc inną wydajność niż printf %s 'a' | xxd.
Niektóre polecenia ( lsna przykład) działają inaczej w zależności od tego, czy standardowym wyjściem jest konsola, czy nie; to ls | catsamo nie lsrobi. Podobnie echo $(ls)będzie działać inaczej niż ls.
Odkładając na lsbok, w ogólnym przypadku, jeśli musisz zmusić to inne zachowanie, to stuff | catjest 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).