Подтвердить что ты не робот

Как сохранить кавычки в аргументах Bash?

У меня есть Bash script, где я хочу сохранить кавычки в переданных аргументах.

Пример:

./test.sh this is "some test"

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

Я попытался использовать \"[email protected]\", но это удаляет кавычки внутри списка.

Как это сделать?

4b9b3361

Ответ 1

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

./test.sh this is '"some test"'

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

Но я бы порекомендовал поместить всю строку между одинарными кавычками:

 ./test.sh 'this is "some test" '

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

#!/bin/bash

echo [email protected]
echo "[email protected]"

Затем вы увидите и протестируете, что происходит при вызове скрипта с разными строками.

Ответ 2

используя "[email protected]", заменит аргументы как список, не перерасшивая их по пробелам (они были разделены один раз, когда была вызвана оболочка script), что обычно является именно тем, что вы хотите, если хотите просто повторить -pass аргументы в другую программу.

Что вы пытаетесь сделать и каким образом он не работает?

Ответ 3

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

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

#!/bin/bash
C=''
for i in "[email protected]"; do 
    i="${i//\\/\\\\}"
    C="$C \"${i//\"/\\\"}\""
done
bash -c "$C"

Итак, все аргументы получают цитату вокруг них (безвредность, если она не была раньше, для этой цели), но мы также избегаем любых экранов, а затем избегаем кавычек, которые уже были в аргументе (синтаксис ${var//from/to} выполняет глобальную подстроку подстроки).

Вы могли бы, конечно, только процитировать материал, который уже имел пробелы в нем, но здесь это не имеет значения. Одна из возможностей script, как это, состоит в том, чтобы иметь определенный предопределенный набор переменных среды (или, с помощью su, запускать материал как определенный пользователь без этого беспорядка для двойного цитирования).


Обновление. Недавно у меня была причина сделать это с помощью POSIX с минимальной разметкой, что приведет к этому script (последний printf выводит командную строку, используемую для вызова script, которую вы должны иметь copy-paste, чтобы вызвать его с эквивалентными аргументами):

#!/bin/sh
C=''
for i in "[email protected]"; do
    case "$i" in
        *\'*)
            i=`printf "%s" "$i" | sed "s/'/'\"'\"'/g"`
            ;;
        *) : ;;
    esac
    C="$C '$i'"
done
printf "$0%s\n" "$C"

Я переключился на '', так как оболочки также интерпретируют такие вещи, как $ и !! в "" -quotes.

Ответ 4

Если было бы безопасно предположить, что аргумент, содержащий пробел, должен быть (и должен быть) указан, вы можете добавить их следующим образом:

#!/bin/bash
whitespace="[[:space:]]"
for i in "[email protected]"
do
    if [[ $i =~ $whitespace ]]
    then
        i=\"$i\"
    fi
    echo "$i"
done

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

$ ./argtest abc def "ghi jkl" $'mno\tpqr' $'stu\nvwx'
abc
def
"ghi jkl"
"mno    pqr"
"stu
vwx"

Вы также можете вставлять литеральные вкладки и новые строки, используя Ctrl - V Tab и Ctrl - V Ctrl - J в двойных или одинарных кавычках вместо использования экранов в $'...'.

Заметка о вставке символов в Bash: если вы используете привязки клавиш Vi (set -o vi) в Bash (Emacs по умолчанию - set -o emacs), вам нужно быть в режиме вставки чтобы вставить символы. В режиме Emacs вы всегда находитесь в режиме вставки.

Ответ 5

Есть два безопасных способа сделать это:

1. Расширение параметров оболочки: ${[email protected]}:

При раскрытии переменной с помощью ${[email protected]}:

Расширение - это строка, представляющая собой значение параметра в кавычках в формате, который можно повторно использовать в качестве входных данных.

Пример:

$ expand-q() { for i; do echo ${[email protected]}; done; }  # Same as for 'i in "[email protected]"'...
$ expand-q word "two words" 'new
> line' "single'quote" 'double"quote'
word
'two words'
$'new\nline'
'single'\''quote'
'double"quote'

2. printf %q "$quote-me"

printf поддерживает внутреннее цитирование. Ручная запись для printf гласит:

%q Заставляет printf выводить соответствующий аргумент в формате, который можно использовать в качестве ввода оболочки.

Пример:

$ cat test.sh 
#!/bin/bash
printf "%q\n" "[email protected]"
$ 
$ ./test.sh this is "some test" 'new                                                                                                              
>line' "single'quote" 'double"quote'
this
is
some\ test
$'new\nline'
single\'quote
double\"quote
$

Обратите внимание, что 2-й способ немного чище, если отображать цитируемый текст человеку.

Связанный: Для bash, POSIX sh и zsh: строка кавычек с одинарными кавычками, а не обратная косая черта

Ответ 6

Как сказал Том Хейл, один из способов сделать это - с помощью printf с помощью %q для quot-escape.

Например:

send_all_args.sh

#!/bin/bash
if [ "$#" -lt 1 ]; then
 quoted_args=""
else
 quoted_args="$(printf " %q" "${@}")"
fi

bash -c "$( dirname "${BASH_SOURCE[0]}" )/receiver.sh${quoted_args}"

send_fewer_args.sh

#!/bin/bash
if [ "$#" -lt 2 ]; then
 quoted_last_args=""
else
 quoted_last_args="$(printf " %q" "${@:2}")"
fi

bash -c "$( dirname "${BASH_SOURCE[0]}" )/receiver.sh${quoted_last_args}"

receiver.sh

#!/bin/bash
for arg in "[email protected]"; do
  echo "$arg"
done

Пример использования:

$ ./send_all_args.sh
$ ./send_all_args.sh a b
a
b
$ ./send_all_args.sh "a' b" 'c "e '
a' b
c "e 
$ ./send_fewer_args.sh
$ ./send_fewer_args.sh a
$ ./send_fewer_args.sh a b
b
$ ./send_fewer_args.sh "a' b" 'c "e '
c "e 
$ ./send_fewer_args.sh "a' b" 'c "e ' 'f " g'
c "e 
f " g

Ответ 7

Мне это нужно для пересылки всех аргументов другому переводчику. То, что оказалось правильным для меня, это:

bash -c "$(printf ' %q' "[email protected]")"

Пример (когда он назван forward.sh):

$ ./forward.sh echo "3 4"
3 4
$ ./forward.sh bash -c "bash -c 'echo 3'"
3

(Конечно, реальный сценарий, который я использую, является более сложным, включая в моем случае nohup, перенаправления и т.д., Но это ключевая часть.)

Ответ 8

Моя проблема была похожа, и я использовал смешанные идеи, размещенные здесь.

У нас есть сервер с PHP script, который отправляет электронные письма. И тогда у нас есть второй сервер, который подключается к 1-му серверу через SSH и выполняет его.

Имя script на обоих серверах одинаково, и оба они фактически выполняются через bash script.

На сервере 1 (локальном) bash script мы имеем только:

/usr/bin/php /usr/local/myscript/myscript.php "[email protected]"

Это находится на /usr/local/bin/myscript и вызывается удаленным сервером. Он отлично работает даже для аргументов с пробелами.

Но тогда на удаленном сервере мы не можем использовать ту же логику, потому что 1-й сервер не получит кавычки из "[email protected]". Я использовал идеи от Джона Мадда и Денниса Уильямсона, чтобы воссоздать массив параметров и параметров с котировками. Мне нравится идея добавления экранированных цитат только тогда, когда в элементе есть пробелы.

Таким образом, удаленный script работает с:

CSMOPTS=()
whitespace="[[:space:]]"
for i in "[email protected]"
do
    if [[ $i =~ $whitespace ]]
    then
        CSMOPTS+=(\"$i\")
    else
        CSMOPTS+=($i)
    fi
done

/usr/bin/ssh "[email protected]$SERVER" "/usr/local/bin/myscript ${CSMOPTS[@]}"

Обратите внимание, что я использую "${CSMOPTS[@]}" для передачи массива параметров на удаленный сервер.

Спасибо за eveyone, который выложил здесь! Это действительно помогло мне!:)

Ответ 9

Изменен unhammer пример использования массива.

printargs() { printf "'%s' " "[email protected]"; echo; };  # http://superuser.com/a/361133/126847

C=()
for i in "[email protected]"; do
    C+=("$i")  # Need quotes here to append as a single array element.
done

printargs "${C[@]}"  # Pass array to a program as a list of arguments.                               

Ответ 10

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

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

val="$3"
echo "Hello World" > "$val"

Ответ 11

Просто используйте:

"${@}"

Например:

# cat t2.sh
for I in "${@}"
do
   echo "Param: $I"
done
# cat t1.sh
./t2.sh "${@}"

# ./t1.sh "This is a test" "This is another line" a b "and also c"
Param: This is a test
Param: This is another line
Param: a
Param: b
Param: and also c

Ответ 12

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

У меня есть функция bash, которая будет искать в папке рекурсивно и grep для поиска строки, проблема заключается в передаче строки с пробелами, такой как "найти эту строку". Передача этого скрипту bash затем примет базовый аргумент $ n и передаст его grep, в этом случае grep полагает, что это разные аргументы. Я решил это, используя тот факт, что когда вы цитируете bash для вызова функции, она группирует элементы в кавычках в один аргумент. Мне просто нужно было украсить этот аргумент кавычками и передать его команде grep.

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

Ответ 13

Как показал Гэри С. Уивер в своих советах по исходному коду, хитрость заключается в том, чтобы вызвать bash с параметром '-c', а затем процитировать следующее.

например

bash -c "<your program> <parameters>"

или же

docker exec -it <my docker> bash -c "$SCRIPT $quoted_args"

Ответ 14

Если вам нужно передать все аргументы bash с другого языка программирования (например, если вы хотите выполнить bash -c или emit_bash_code | bash), используйте это:

  • экранируйте все символы одинарных кавычек, которые у вас есть с '\''.
  • затем поместите результат в кавычки

Таким образом, аргумент abc'def будет преобразован в 'abc'\''def'. Символы '\'' интерпретируются следующим образом: уже существующее цитирование заканчивается первой первой кавычкой, затем следует экранированная одиночная одинарная кавычка \', затем начинается новое цитирование.