Как заменить цитируемые строки из нескольких слов в качестве аргументов? - PullRequest
13 голосов
/ 28 февраля 2012

Я пытаюсь подставить строковую переменную, содержащую несколько слов в кавычках, в качестве параметра команды.

Таким образом, учитывая следующий пример сценария (обратите внимание на -x в шебанге, который приводит к записи вывода в 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


Вторая строка показывает, что на самом деле передается команде; bash добавил одинарные кавычки к каждому слову в строке. Если вместо этого я вместо этого цитирую «$ myArg», то же самое происходит, но для всей строки, а не для каждого слова.

Теперь представьте, что вместо echo мы передаем строку в программу, где некоторые аргументы должны быть в кавычках, например, "*" (который не должен расширяться оболочкой).

Чтобы уточнить, я не хочу, чтобы во время расширения вообще добавлялись одинарные кавычки. Как мне этого добиться?

Ответы [ 4 ]

16 голосов
/ 28 февраля 2012

Не используйте кавычки, используйте массив (см. 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" (которое может вызвать некоторые действительно неприятные ошибки, если вы не будете осторожны), либо проанализировать это самостоятельно (что будет сложно).

6 голосов
/ 28 февраля 2012

Если вы хотите передать значение переменной в качестве параметра (99% случаев на SO), просто используйте правильные кавычки :

arg="foo bar"
command "$arg"

Если вы хотите передать несколько аргументов, используйте массивы:

args=("foo bar" "baz ban" bay)
command "${args[@]}"
0 голосов
/ 08 июня 2018

Существует портативный способ разбить, расширить переменную, но оставить пробелы.Массивы Bash не нужны.Тире (Ubuntu / bin / sh) тоже будет работать.

Используйте некоторый символ для разделения аргументов, который определенно не используется внутри аргументов.В приведенном ниже примере используется точка с запятой, но это может быть символ новой строки или другой символ.При расширении списка аргументов временно измените переменную IFS на новую строку.Восстановите IFS к исходному значению как можно скорее, даже если это означает выполнение этого в цикле.Если цикл не гарантированно выполняется хотя бы один раз, делайте это и после цикла.

#! /bin/sh
arg_list='hello world;have a nice day'
save_IFS="$IFS"
IFS=';'
for i in $arg_list; do
  IFS="$save_IFS"
  echo "$i"
done
IFS="$save_IFS"

Обратите внимание, что каждый расширенный аргумент печатается индивидуально.

$ ./test.sh
hello world
have a nice day
0 голосов
/ 28 февраля 2012

Я не думаю, что он делает то, о чем вы думаете.

[~]$ 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

Теперь, если вы добавите расширение * или глобальный путь в одно из них, Bash в этот момент расширит его, если вы не избежите его, илииспользуйте одинарные кавычки в вашей буквальной команде.

[~]$ cargs "string is:" $myArg *
19
[~]$ cargs "string is:" $myArg "\*"
4
[~]$ cargs "string is:" $myArg '*'
4
...