Как я могу запустить переменную bash как команду без дополнительных кавычек?

Как я могу запустить переменную bash как команду без дополнительных кавычек?

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

Вот пример скрипта. Команда, exampleзапущенная в этом примере скрипта, очевидно, ничего не делает и просто скажет command not found, однако вы все равно можете запустить скрипт и увидеть, о чем я говорю, потому что я добавил -xв #!/bin/bashстроку, чтобы вывести точную выполняемую команду.

Пример:

#!/bin/bash -x

#command typed explicitly
example -options "-i filename"

#command stored in string first
commandstring='example -options "-i filename"'
echo "running command: ${commandstring}"
${commandstring}

Результат выполнения этого скрипта для меня следующий (игнорируя две ошибки «команда не найдена»):

+ example -options '-i filename'
+ commandstring='example -options "-i filename"'
+ echo 'running command: example -options "-i filename"'
running command: example -options "-i filename"
+ example -options '"-i' 'filename"'

Итак, вы можете видеть, что первая строка, конечно же, запускается, как и ожидалось, с указанием параметра командной строки:

-i filename

Однако, хотя echoкоманда выводит строку таким образом, что она также будет выполнена идеально, при помещении строки в командную строку она изменяется, и передаваемый параметр становится

'"-i' 'имя_файла''

который содержит дополнительные символы кавычек, и это приводит к тому, что команда, которую я использую в своем реальном скрипте, не выполняется.

Есть ли способ предотвратить это?

решение1

Если вы используете bash, самый простой способ сохранить команду — поместить ее в массив. Если команда, которую вы хотите выполнить, это:

example -options "-i filename"

Вы можете сохранить его в переменной массива с помощью:

commandline=(example -options "-i filename")

Затем вы можете запустить сохраненную команду в том виде, в котором она есть, используя @-расширение массива внутри двойных кавычек:

"${commandline[@]}"

Главное, что нужно знать здесь, это то, что оболочка обрабатывает символы кавычек ( "'\) по-разному, когда они вводятся непосредственно в командную строку, и когда она находит их внутри расширения переменной, например, в вашем ${commandstring}. В командной строке символы кавычек имеют специальную функцию кавычек. Внутри расширения параметра они являются обычными неспециальными символами. Таким образом, "-i filename"является одним словом, которое при вводе в командной строке анализируется как -i filename, но те же символы в переменной расширяются до слов "-iи filename".


БашFAQ 50освещает эту тему гораздо более подробно.

Связанный контент