Самое время решить эту головоломку, которая беспокоила меня годами ...
Я встречался с этим время от времени и думал, что это путь:
$(comm "$(arg)")
И думал, что мое мнение было решительно подтверждено опытом. Но я больше не уверен в этом. Shellcheck тоже не может определиться . Это оба:
"$(dirname $0)"/stop.bash
^-- SC2086: Double quote to prevent globbing and word splitting.
И:
$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.
Какая логика позади?
(Это версия Shellcheck 0.4.4, кстати.)
bash
quoting
command-substitution
Tomasz
источник
источник
"$(dirname "$0")"/stop.bash
? Кажется, работает ... Что за история?shell_level_1 $(shell_level_2) shell_level_1
: когда вы внутри,$(....)
вы вводите «подуровень» оболочки, НО вы можете писать в нем, как если бы вы были на начальном уровне (то есть вы можете писать напрямую"
вместо\"
и т. д.). Пример:touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to
найти \ "/ tmp / файл \" `иprint \$5
. Без$(...)
необходимости: оболочка адаптируется к новому уровню, и вы можете писать напрямую, как будто ваш переводчик теперь тоже на этом уровне.Ответы:
Вам нужно использовать
"$(somecmd "$file")"
.Без кавычек путь с пробелом будет разделен в аргументе
somecmd
, и он будет нацелен на неправильный файл. Так что вам нужны цитаты изнутри.Любые пробелы в выходных данных
somecmd
также будут вызывать расщепление, поэтому вам нужны кавычки вне всей подстановки команд.Кавычки внутри подстановки команд не влияют на кавычки вне ее. Собственное справочное руководство Bash не слишком ясно об этом, но BashGuide прямо упоминает об этом . Текст в POSIX также требует, так как «любой действительный сценарий оболочки» допускается внутри
$(...)
:Пример:
а. Без кавычек,
dirname
обрабатывает как./space
иhere/foo
:б. Кавычки внутри,
dirname
процессы./space here/foo
, дачи./space here
, которые делятся на две части:с. Кавычки снаружи,
dirname
обрабатывают оба./space
иhere/foo
выводят на отдельных строках, но теперь две строки образуют один аргумент :д. Цитаты как внутри, так и снаружи, это дает правильный ответ:
(возможно, было бы проще, если бы
dirname
только обработал первый аргумент, но это не показало бы разницу между случаями a и c.)Обратите внимание, что с
dirname
(и, возможно, с другими) вам также нужно добавить--
, чтобы предотвратить использование имени файла в качестве опции на случай, если оно начинается с тире, поэтому используйте"$(dirname -- "$file")"
.источник
$( )
создает новый контекст, поэтому кавычки внутри него не зависят от кавычек вне его. И вы вообще хотите цитаты в обоих контекстах.