Najwyższy czas rozwiązać tę zagadkę, która niepokoi mnie od lat ...
Spotykałem się z tym od czasu do czasu i myślałem, że to jest właściwa droga:
$(comm "$(arg)")
I pomyślałem, że moje zdanie jest mocno poparte doświadczeniem. Ale nie jestem już taki pewien. Shellcheck też nie może się zdecydować. Oba są:
"$(dirname $0)"/stop.bash
^-- SC2086: Double quote to prevent globbing and word splitting.
I:
$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.
Jaka jest logika?
(Jest to wersja Shellcheck 0.4.4, btw.)
bash
quoting
command-substitution
Tomasz
źródło
źródło
"$(dirname "$0")"/stop.bash
? Wydaje się, że działa ... Jaka jest historia?shell_level_1 $(shell_level_2) shell_level_1
gdy jesteś w środku$(....)
, wchodzisz w „podpoziom” powłoki, ALE możesz pisać w niej tak, jakbyś był na poziomie podstawowym (tzn. możesz pisać bezpośrednio"
zamiast\"
, itp.). np.touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to
znajdź \ "/ tmp / plik \" iprint \$5
. Bez$(...)
potrzeby: powłoka dostosowuje się do nowego poziomu i możesz pisać bezpośrednio, tak jakby Twój tłumacz również był na tym poziomie.Odpowiedzi:
Musisz użyć
"$(somecmd "$file")"
.Bez cudzysłowów ścieżka ze spacją zostanie podzielona w argumencie do
somecmd
i będzie kierowana na niewłaściwy plik. Potrzebujesz więc cytatów w środku.Wszelkie spacje na wyjściu
somecmd
również powodują dzielenie, więc potrzebujesz cudzysłowów na zewnątrz całego podstawienia polecenia.Cytaty w podstawieniu polecenia nie mają wpływu na cytaty poza nim. Podręcznik referencyjny Bash nie jest zbyt jasny, ale BashGuide wyraźnie o tym wspomina . Tekst w POSIX wymaga również to, jak „każdej ważnej skryptu powłoki” jest dozwolone wewnątrz
$(...)
:Przykład:
za. Brak cytatów,
dirname
przetwarza zarówno./space
ahere/foo
:b. Cytaty wewnątrz,
dirname
procesy./space here/foo
, dawanie./space here
, które dzieli się na dwa:do. Cytuje na zewnątrz,
dirname
przetwarza oba./space
ihere/foo
, wyprowadza na osobnych wierszach, ale teraz te dwa wiersze tworzą pojedynczy argument :re. Cytuje zarówno wewnątrz, jak i na zewnątrz, daje to prawidłową odpowiedź:
(byłoby to prawdopodobnie prostsze, gdyby
dirname
przetworzył tylko pierwszy argument, ale nie pokazałoby różnicy między przypadkami a i c.)Zauważ, że wraz z
dirname
(i prawdopodobnie innymi) musisz również dodać--
, aby zapobiec traktowaniu nazwy pliku jako opcji na wypadek, gdyby zaczynało się od myślnika, więc użyj"$(dirname -- "$file")"
.źródło
$( )
tworzy nowy kontekst, więc cytaty w nim są niezależne od cudzysłowów poza nim. I ogólnie chcesz cytatów w obu kontekstach.