Как правильно процитировать вложенные аргументы вложенной оболочки?

Как передать строку с пробелами в команду, которая возвращает себе строку с пробелами?

Я попробовал следующие четыре версии.

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")")")"

Гораздо проще.

Другие вопросы по тегам