Как заменить цитируемые, многословные строки в качестве аргументов?
Я пытаюсь подставить строковую переменную, содержащую несколько цитированных слов, в качестве параметра для команды.
Таким образом, в следующем примере script (Обратите внимание на -x в shebang, что заставляет вывод записываться в stderr),
#!/bin/bash -x
myArg="\"hello\" \"world\""
echo "string is:" $myArg
exit
Что дает нам,
+ myArg='"hello" "world"'
+ echo 'string is:' '"hello"' '"world"'
string is: "hello" "world"
+ exit
Строка 2 показывает, что фактически передается команде; bash добавляет одинарные кавычки к каждому слову в строке. Если я вместо этого цитирую "$ myArg", то это происходит, но для всей строки, а не для каждого слова.
Теперь представьте, что вместо echo
мы передаем строку в программу, где некоторые из аргументов должны быть кавычками, например "*"
(которые не должны быть расширены оболочкой).
Чтобы уточнить, я не хочу, чтобы одиночные кавычки были добавлены вообще во время расширения. Как я могу это достичь?
Ответы
Ответ 1
Не используйте кавычки, используйте массив (см. BashFAQ # 050):
$ myArgs=("hello" "world" "multiword arg with * ?")
+ myArgs=("hello" "world" "multiword arg with * ?")
$ echo "${myArgs[@]}"
+ echo hello world 'multiword arg with * ?'
hello world multiword arg with * ?
Если это действительно должно быть в виде строк с кавычками внутри строки, вам придется либо использовать что-то вроде eval "echo $myArg"
(что может вызвать некоторые действительно неприятные ошибки, если вы не будете осторожны) или проанализируйте его самостоятельно (что будет сложно).
Ответ 2
Если вы хотите передать значение переменной в качестве параметра (99% случаев на SO), просто используйте quoting:
arg="foo bar"
command "$arg"
Если вы хотите передать несколько аргументов, используйте массивы:
args=("foo bar" "baz ban" bay)
command "${args[@]}"
Ответ 3
Я не думаю, что он делает то, что, по вашему мнению, делает.
[~]$ myArg="\"hello\" \"world\""
[~]$ echo "string is:" $myArg
string is: "hello" "world"
Я не вижу лишних кавычек любого типа - echo
получает три строки аргументов.
[~]$ cargs(){ echo $#; }
[~]$ cargs "string is:" $myArg
3
Bash будет сначала расширять переменную, поэтому
cargs "string is:" $myArg
становится (хотя и без литеральных обратных косых черт - вот почему экранирование строки - это PITA)
cargs "string is:" "\"hello\"" "\"world\""
И массив args:
0x00:string is:0
0x0B:"hello"0
0x13:"world"0
0x1B:0
Теперь, если вы добавите расширение *
или glob path в одном из них, Bash в этот момент расширит его, если вы не убежите от него, или используйте одинарные кавычки в своей литеральной команде.
[~]$ cargs "string is:" $myArg *
19
[~]$ cargs "string is:" $myArg "\*"
4
[~]$ cargs "string is:" $myArg '*'
4