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



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



пример:



./test.sh this is "some test"


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



Я пробовал использовать "$@", но это удаляет кавычки внутри списка.



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

769   11  

11 ответов:

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

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

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

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

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

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

#!/bin/bash

echo $@
echo "$@"

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

С помощью "$@" будет заменять аргументы в виде списка, без повторного разбиения их на пробелы (они были разделены один раз, когда был вызван сценарий оболочки), что, как правило, именно то, что вы хотите, если вы просто хотите повторно передать аргументы в другую программу.

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

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

вот версия, которую можно использовать, если вы хотите передать все аргументы в виде одного большого аргумента в кавычках %s\n" "$C"

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

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

#!/bin/bash
whitespace="[[:space:]]"
for i in "$@"
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 -VTab и Ctrl -VCtrl -J в двойных или одинарных кавычках вместо того, чтобы использовать escapes внутри $'...'.

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

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

1. расширение параметров оболочки:${variable@Q}:

при расширении переменной через ${variable@Q}:

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

пример:

$ expand-q() { for i; do echo ${i@Q}; done; }  # Same as for `i in "$@"`...
$ 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" "$@"
$ 
$ ./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:строка кавычек с одинарными кавычками, а не с обратной косой чертой

как сказал том Хейл, один из способов сделать это-с printf используя %q цитировать-побег.

например:

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 "$@"; 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

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

printargs() { printf "'%s' " "$@"; echo; };  # http://superuser.com/a/361133/126847

C=()
for i in "$@"; 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.                               

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

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

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

на сервере 1 (локальный) скрипт bash у нас есть только:

/usr/bin/php /usr/local/myscript/myscript.php "$@"

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

но тогда на удаленном сервере, мы не можем использовать ту же логику, потому что 1-й сервер не получает котировки от "$@". Я использовал идеи от JohnMudd и Dennis Williamson, чтобы воссоздать массив опций и параметров с цитатами. Мне нравится идея добавления экранированных цитат только тогда, когда в элементе есть пробелы.

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

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

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

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

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

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

bash -c "$(printf ' %q' "$@")"

пример (при имени как forward.sh):

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

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

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

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

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

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

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

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

Comments

    Ничего не найдено.