Я пытаюсь создать скрипт, который должен сохранить команду для запуска в виде строки. Строка должна содержать кавычки, и при попытке ее выполнить 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освещает эту тему гораздо более подробно.