Bash и Double-Quotes переходят в argv

Я повторил этот пример, чтобы сохранить его простым, но то, что я пытаюсь сделать, это получить вложенную строку с двумя кавычками в качестве одного значения argv, когда shell bash выполняет его.

Вот пример скрипта:

set -x command1="key1=value1 \"key2=value2 key3=value3\"" command2="keyA=valueA keyB=valueB keyC=valueC" echo $command1 echo $command2 

выход:

 ++ command1='key1=value1 "key2=value2 key3=value3"' ++ command2='keyA=valueA keyB=valueB keyC=valueC' ++ echo key1=value1 '"key2=value2' 'key3=value3"' key1=value1 "key2=value2 key3=value3" ++ echo keyA=valueA keyB=valueB keyC=valueC keyA=valueA keyB=valueB keyC=valueC 

Я также тестировал, что, когда вы делаете все в командной строке, nested котировочное сообщение IS устанавливается как одно значение argv. т.е.

 prog.exe argument1 "argument2 argument3" argv[0] = prog.exe argv[1] = argument1 argv[2] = argument2 argument3 

Используя приведенный выше пример:

 command1="key1=value1 \"key2=value2 key3=value3\"" 

Ошибка в том, что мой argv возвращается назад:

 arg[1] = echo arg[2] = key1=value1 arg[3] = "key2=value2 arg[4] = key3=value3" 

где я действительно хочу, чтобы значение argv [3] было «key2 = value2 key3 = value3»

Я заметил, что debug (set -x) показывает одиночную кавычку в точках, где мои аргументы разбиваются, что своего рода указывает на то, что он думает об аргументах в этой точке останова … просто не уверен.

Любая идея, что на самом деле происходит здесь? Как изменить сценарий?

Заранее спасибо.

Что происходит, так это то, что ваши вложенные кавычки являются буквальными и не анализируются отдельными аргументами оболочки. Лучший способ справиться с этим с помощью bash – использовать массив вместо строки:

 args=('key1=value1', 'key2=value2 key3=value3') prog.exe "${args[@]}" 

В Bash FAQ50 есть еще несколько примеров и вариантов использования для динамических команд.

Какой-то сумасшедший «ответ» заключается в том, чтобы установить IFS на двойную цитату (save / restore original IFS):

 SAVED_IFS=$IFS IFS=$'\"' prog.exe $command1 IFS=$SAVED_IFS 

Это как-то иллюстрирует расщепление слов, которое происходит на некотируемых аргументах, но не влияет на переменные или текст внутри котировок ".." . Текст внутри двойных кавычек (после различных расширений) передается программе как один аргумент. Однако голой переменной $ command1 (без кавычек) претерпевает разделение слов, которое не заботится о " внутри переменной (беря ее буквально). Глупый взлом IFS заставляет разбивать слова на " . Также остерегайтесь конечного пробела в конце argv [1], который появляется из-за разбиения слова на " границе».

Ответ jordanm намного лучше для использования в производстве, чем у меня 🙂 Массив цитируется, т. е. каждый элемент массива расширяется как отдельная строка, и после этого словосочетание не происходит. Это важно. Если он не сортируется, как ${args[@]} он будет разбит на три аргумента вместо двух.