Как правильно процитировать вложенные аргументы вложенной оболочки?
Как передать строку с пробелами в команду, которая возвращает себе строку с пробелами?
Я попробовал следующие четыре версии.
arg='one arg'
arg() { echo "arg: $1"; }
printf '1 |%s|\n' $(arg "$arg")
printf '2 |%s|\n' "$(arg $arg)"
printf '3 |%s|\n' "$(arg \"$arg\")"
printf '4 |%s|\n' "$(arg '$arg')"
Все они терпят неудачу:
1 | arg: | 1 | один | 1 |arg| 2 |arg: one| 3 |arg: "один | 4 |arg: $arg|
Как получить этот результат?
? | арг: один арг |
1 ответ
Синтаксис
С помощью $()
создает новый контекст цитирования. Таким образом, двойные кавычки внутри подстановки команд полностью независимы от тех, которые находятся за ее пределами, и при закрытии внешних двойных кавычек начинается новая и независимая пара.
arg='one arg'
arg() { echo "arg: $1"; }
printf '? |%s|\n' "$(arg "$arg")"
... правильно испускает:
? |arg: one arg|
Обоснование (и история)
С помощью приведенного выше синтаксиса легко добавить дополнительные слои вложенности:
printf '%s |%s|\n' "$(arg "$(arg "$arg")")"
С синтаксисом обратного POSIX вместо POSIX вместо $()
Ваша попытка № 3 была бы правильной:
printf '3 |%s|\n' "`arg \"$arg\"`"
Тем не менее, необходимость обратной косой черты как кавычек, так и вложенных обратных кавычек становится неосуществимой быстро по мере увеличения глубины вложения. Добавление еще одного вложенного arg
делает это:
printf '3a |%s|\n' "`arg \"\`arg \\\"$arg\\\"\`\"`"
Добавление двух дополнительных слоев (таким образом, три arg
всего вызовов функций), что еще хуже:
printf '3b |%s|\n' "`arg \"\`arg \\\"\\\`arg \\\\\\\"$arg\\\\\\\"\\\`\\\"\`\"`"
В то время как с современным синтаксисом это просто:
printf '3b |%s|\n' "$(arg "$(arg "$(arg "$arg")")")"
Гораздо проще.