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

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

Пример:

./test.sh this is "some test"

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

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

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


person zlack    schedule 03.11.2009    source источник
comment
\"$@\" неверен - он добавляет буквальные кавычки к первому и последнему аргументам. "$@", без обратных слэшей, правильно: в нем кавычки чисто синтаксические. См. BashFAQ #50 для объяснения того, почему передача списков аргументов в виде строк изначально неверна в оболочке. .   -  person Charles Duffy    schedule 10.03.2017
comment
Чарльз прав. Если вы хотите передать все аргументы другому сценарию или функции, используйте $@ (не выходя из кавычек).   -  person CompEng88    schedule 10.10.2017
comment
См. этот ответ: Разница между одинарными и двойными кавычками в Bash.   -  person codeforester    schedule 19.12.2017


Ответы (14)


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

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

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

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

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

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

#!/bin/bash

echo $@
echo "$@"

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

person Randy Sugianto 'Yuku'    schedule 03.11.2009
comment
Как это может быть принятым ответом? Это требует, чтобы вызывающая сторона скрипта знала, что он использует двойные кавычки, хотя это может быть обработано в сценарии без изменения способа, которым вызывающая сторона строит список параметров. - person Patrick Cornelissen; 02.03.2016
comment
Если у вас нет контроля над ./test.sh, то это правильный ответ, но если вы создаете ./test.sh, то ответ от Криса Додда лучшее решение. - person sanscore; 29.03.2016
comment
Это уместно не только в том случае, если у вас нет контроля над test.sh, но и только в сценарии, где test.sh написано для небезопасного использования eval. И, честно говоря, если что-то использует eval небезопасно, это, вероятно, довольно веская причина, чтобы прекратить использовать эту штуку. - person Charles Duffy; 10.03.2017
comment
Wtf не так с людьми здесь. Как это принятый ответ. Он передает ответственность вызывающей стороне. - person Arunav Sanyal; 12.05.2017
comment
Хотя это правильно, в основном вы не печатаете ответ. Это на самом деле не отвечает на вопрос. Он также не придерживается правил SO для ответов. Во всяком случае, более информативное объяснение того, почему вы этого не делаете, можно найти здесь stackoverflow.com/a/10836225/4687565 - person Dimitry; 30.06.2017
comment
Я расширил ответ, потому что с первого взгляда не было видно, в чем заключались различия обоих вызовов. Прошло некоторое время, прежде чем я увидел одинарные кавычки в ответе @yuku. - person Sedat Kilinc; 27.06.2018
comment
Я беру это назад, на мгновение я прочитал это как $* вместо $@, действительно, это правильный ответ. Ссылка здесь разъясняет это Bash $* и $@. - person Claudiu; 01.06.2020

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

Обратите внимание, что это особая форма, и она распознается как таковая, только если выглядит именно так. Если вы добавите что-нибудь еще в кавычки, результат будет объединен в один аргумент.

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

person Chris Dodd    schedule 03.11.2009
comment
Я думаю, он имеет в виду, что кавычки являются частью строки аргумента, а не частью синтаксиса bash. - person Alex Brown; 12.05.2014
comment
Чтобы уточнить, этот ответ идеален: он, как и другие ответы, пытается повторно добавить цитату вокруг каждого аргумента. Это НЕ просто добавляет две кавычки вокруг всего списка аргументов, но вокруг каждого отдельного аргумента. - person qwertzguy; 15.05.2014
comment
@qwertzguy неверен. Двойные кавычки будут удалены до того, как переменная войдет в список аргументов. - person Donal Lafferty; 03.11.2014
comment
Это самый популярный ответ. Хотя это правильно само по себе, на самом деле это не решает вопрос. - person Torsten Bronger; 26.01.2016
comment
@TorstenBronger: Поскольку вопрос совершенно неясен, это отвечает на мое лучшее предположение о том, чего на самом деле хочет ОП. - person Chris Dodd; 26.01.2016
comment
Да, согласен, непонятно. И что ваш ответ имеет свою ценность сам по себе. И я действительно не жалею, что вы голосуете. Но все же... это ответ на другой вопрос. :) - person Torsten Bronger; 26.01.2016
comment
@TorstenBronger: положительные отзывы указывают на то, что это ответ на вопрос, который возникает у большинства людей, когда они ищут свой вопрос и попадают на эту страницу, даже если это не ответ на то, что пытался спросить ОП. - person Chris Dodd; 14.02.2016
comment
как бы вы использовали формат $@ для передачи параметров в xargs ? будет ли это работать без трюка с повторным цитированием? Не думаю - person Hofi; 13.04.2016
comment
@Hofi: xargs никоим образом не переосмысливает и не анализирует свои аргументы, поэтому в дополнительных цитировании не должно быть необходимости (если вы не делаете что-то вроде xargs sh ...) - person Chris Dodd; 14.04.2016
comment
@ChrisDodd, я сейчас в замешательстве, объясните, пожалуйста, как xargs сделает это в следующем случае echo "$@" | xargs -t defaults write "${BUNDLEID}" "${KEY}" -dict в этом случае, если один из входных параметров подобен параметру с пробелами, он не будет работать без дополнительного трюка с цитированием - person Hofi; 14.04.2016
comment
@Hofi: Вы можете сделать что-то вроде find <some find args> | xargs program "$@", и он передаст аргументы исходного скрипта или функции в program без повторной интерпретации. Если вы хотите, чтобы xargs не разбивал свой INPUT на пробелы, вам нужно что-то вроде { for a in "$@"; do echo -en "$a\\x0"; done; } | xargs -0 program - person Chris Dodd; 14.04.2016
comment
@ChrisDodd извините, но ни один из вышеперечисленных способов не будет работать, если вам нужно просто передать строки с пробелами внутри, попробуйте эти echo "nospace" "yes space" | xargs ls "$@" echo "nospace" "yes space" | xargs -0 ls echo '"nospace"' '"yes space"' | xargs ls В первом случае 3 отдельных имени переданы ls с помощью xargs, а во втором случае только одно (как и ожидалось) только 3-й корпус работает корректно (не удивительно) - person Hofi; 15.04.2016
comment
@Hofi: Это все потому, что вам нужны правильные кавычки для echo - xargs и "$@" не имеют значения. Попробуйте echo -ne "nospace\x0yes space\x0", как я предложил. - person Chris Dodd; 15.04.2016
comment
@TorstenBronger, это абсолютно точно отвечает на вопрос, если то, что вы делаете, - это передача полученных вами аргументов - это единственный контекст, в котором имеет смысл сохранять кавычки. Если ваш скрипт был запущен с ./yourscript this is "some test", то запуск ./anotherscript "$@" передаст this, is и some test как три разных аргумента в anotherscript, как если бы пользователь запустил ./anotherscript this is "some test". - person Charles Duffy; 10.03.2017
comment
@Hofi, xargs - это особый случай, и общепризнанно, что он сломан по дизайну (поскольку он пытается выполнить разделение строк, подобное оболочке, на своем буквальном вводе). Действительно, если вы посмотрите на авторитетные ссылки, такие как Wooledge wiki вы обнаружите предупреждения вроде: xargs по умолчанию чрезвычайно опасен и никогда не должен использоваться без нестандартного расширения -0.. Тем не менее, xargs выводит из кавычек только свой стандартный ввод, но его вектор аргументов. - person Charles Duffy; 10.03.2017
comment
@Hofi, ... таким образом, запуск xargs something "$@" абсолютно действителен - когда вы отправляете контент на stdin из xargs, необходимы такие меры предосторожности, как printf '%s\0' "$@" | xargs -0 something. - person Charles Duffy; 10.03.2017
comment
Это определенно не тот ответ, который мы ищем, даже при наибольшем голосовании. Пример, почему нам это нужно, например, мне нужно использовать ssh host -t remoteCmd $@, удаленная команда ожидает некоторый аргумент со строкой с пробелами между которыми нам нужно сохранить кавычки. - person Jianwu Chen; 26.01.2021
comment
@JianwuChen: вам нужны кавычки вокруг $@ -- ssh host -t remoteCmd "$@". Специальное расширение не применяется, если вы включаете в кавычки что-либо еще. - person Chris Dodd; 26.01.2021

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

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
$

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

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

person Tom Hale    schedule 13.09.2016
comment
Это сработало для меня. В функции, которую я использовал: local _quoted=$( printf ' %q' $@ ) Этот ответ выглядит наиболее надежным. - person Laurent Caillette; 07.11.2017
comment
Интересно, но он добавляет обратную косую черту к пробелам и таким символам, как bang. В некоторых случаях это не имеет значения, но преобразует одиночный ! к /! что не работает для меня. - person Elliptical view; 21.02.2018
comment
! необходимо в кавычках: Без кавычек: $ echo !foo -bash: !foo: event not found В кавычках: $ echo \!foo !foo - person Tom Hale; 26.02.2018
comment
1-й метод expand-q имеет ошибку: ${i@Q} должно быть ${i:Q}, иначе он не работает с bash: ${i@Q}: bad substitution - person arielf - Reinstate Monica; 31.05.2018
comment
@arielf Какая версия bash? Это работает, как показано на $BASH_VERSION 4.4.19(1)-release. То, что вы делаете, вероятно, является побочным эффектом ${parameter:offset}, где offset равно 0 (возможно, потому, что atoi() из Q дает 0). - person Tom Hale; 31.05.2018
comment
Это может быть причиной. У меня Ubuntu 16.04.4 (LTS). Последний bash в этой системе 4.3.48(1)-release - person arielf - Reinstate Monica; 02.06.2018
comment
Я обнаружил, что ${*@Q} очень полезен для передачи всех аргументов командной строки в последующий вызов оболочки, в моем случае один из-за вызова sg для изменения группы. Спасибо за этот ответ! - person MvG; 31.08.2019
comment
@MvG Хотел бы я раньше столкнуться с таким комментарием, как ваш; Я делаю точно то же самое! Я могу подтвердить, что ${*@Q} является идеальным решением в конце моих долгих поисков - person forresthopkinsa; 10.07.2021

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

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

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

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

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


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

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

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

person unhammer    schedule 04.01.2012
comment
Вместо этого использовать массив? Я опубликую пример ниже. - person JohnMudd; 01.04.2015
comment
Это почти идеально, но я бы предложил одну небольшую модификацию — экранирование всех ` before appending to $C`, то есть добавление i="${i//\\/\\\\}", иначе такие аргументы, как "\\\"asdf", не сработают. - person Matěj Hrazdíra; 24.07.2016
comment
Хороший улов! Спасибо, отредактировал и добавил. Теперь я могу сделать $ ./escape-args-to-bash echo "\\\"asdf", чтобы получить \"asdf, точно так же, как $ echo "\\\"asdf" дает \"asdf. (В случае, если приведенный выше комментарий не редактируется, единственный `, вероятно, должен был быть обратной косой чертой в обратных кавычках, которая вместо этого ускользала от обратной косой черты - есть ли здесь следствие закона Мафри? :)) - person unhammer; 25.07.2016
comment
@unhammer Большое спасибо, это работает потрясающе! - person Pieter Vogelaar; 10.01.2019
comment
ℹ️ То же, что и просто: "${@@Q}" - person Alberto Salvia Novella; 19.05.2021
comment
О, интересно, как ты это называешь? Однако похоже, что он не делает то же самое, поскольку он разбивает его на несколько параметров (во многом как "$@"), поэтому вы не можете использовать его в качестве единственного аргумента -c — также только для bash. - person unhammer; 19.05.2021
comment
man bash говорит, что это преобразование параметра. Можно использовать это в bash-версии вместо замены регулярного выражения, давая C=''; for i in "$@"; do C="$C ${i@Q}"; done; bash -c "$C" - person unhammer; 19.05.2021

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

#!/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-V Tab и Ctrl -V Ctrl-J в двойных или одинарных кавычках вместо экранирования внутри $'...'.

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

person Dennis Williamson    schedule 03.11.2009
comment
Но как проверить, процитировал ли пользователь, скажем, 1-й аргумент? - person Tony Barganski; 09.11.2018
comment
@TonyBarganski: оболочка удаляет кавычки, когда аргументы обрабатываются до того, как они будут переданы принимающей их программе. Невозможно определить, были ли в аргументе внешние кавычки. - person Dennis Williamson; 09.11.2018

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

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

Пример (при названии forward.sh):

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

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

person isarandi    schedule 16.05.2018

Как сказал Том Хейл, один из способов сделать это — с помощью 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
person Gary S. Weaver    schedule 03.03.2017
comment
Это отличный пример, поскольку он содержит воспроизводимый тест для пересылки аргументов через что-то вроде sh -c. Более того, это работает ;-). Не все остальные. - person Dave Abrahams; 11.09.2020

Изменен пример 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.                               
person JohnMudd    schedule 01.04.2015
comment
Можно ли использовать "${C[@]}" в качестве аргумента для bash -c? Например. если ваш скрипт был вызван с аргументами echo foo\"bar"'"fie - person unhammer; 03.02.2016
comment
например foo=( echo bar\"fie"'"fum ); C='';for i in "${foo[@]}"; do C="$C \"${i//\"/\\\"}\""; done; bash -c "$C" дает bar"fie'fum - person unhammer; 03.02.2016
comment
Хотя код выглядит чище, вы все еще теряете кавычки - person Christian Rondeau; 01.10.2016

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

У нас есть сервер с 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[@]}" для передачи массива параметров на удаленный сервер.

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

person Gus Neves    schedule 29.01.2017
comment
приведенное выше немного терпит неудачу: -opt=value становится -opt=value - person sdive; 06.02.2017
comment
Я не использую = в своих сценариях, но поскольку \" добавляются только при обнаружении пробелов, -opt="value" на самом деле станет -opt=value. что-то вроде -opt="another value" будет отправлено как "-opt=another value", но поскольку моя установка отправляет его в другой скрипт на другом компьютере, он все равно интерпретируется как один токен, как и предполагалось. Удаленный скрипт получает -opt=another value как одиночный токен без кавычек. Однако все по-другому, если работает локально. Например, вам даже не нужно избегать \". - person Gus Neves; 19.04.2017

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

"${@}"

Например:

# 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
person FrameGrace    schedule 08.11.2018
comment
Это не позволяет пересылать аргументы вызову bash -c. Для этого вам нужно что-то вроде stackoverflow.com/a/42588600/125349 - person Dave Abrahams; 11.09.2020

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

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

val="$3"
echo "Hello World" > "$val"
person mouviciel    schedule 03.11.2009

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

e.g.

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

or

docker exec -it <my docker> bash -c "$SCRIPT $quoted_args"
person Lars    schedule 22.01.2019

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

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

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

person Tom Orsi    schedule 20.04.2018

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

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

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

person VasiliNovikov    schedule 20.08.2019
comment
Нет. Не экранируйте аргументы как текст, встроенный в код; вместо этого используйте интерфейс другого языка программирования, который позволяет передавать массив аргументов и передавать каждый элемент в своем собственном элементе массива. Это означает, что люди никогда не должны использовать system(); к счастью, его недостатки были признаны на протяжении десятилетий, так что это редко единственный выбор. - person Charles Duffy; 09.06.2020
comment
В Python, например, можно передать массив, а не строку, вызову subprocess-семейства. В C можно использовать execv или posix_spawn. В Java можно использовать один из интерфейсов на основе массивов в Runtime.exec(); и т. д. и т. д. - person Charles Duffy; 09.06.2020
comment
@CharlesDuffy Извините, но мой ответ начинается со слова если. Посмотрите, например, если это недостаточно ясно... Если вы можете просто вызвать CLI, используя массив аргументов, конечно, это лучше. Однако в ситуации, которую я описываю, это просто невозможно (bash -c или another_program | bash). - person VasiliNovikov; 09.06.2020
comment
Это абсолютно возможно. subprocess.Popen(['bash', '-c', 'code that uses "$1" and "$2"', "_", "value for $1", "value for $2"]), f/e, запускает bash из Python, передавая два значения таким образом, чтобы они не попадали в код. Шаблону pipe-to-bash просто не следует следовать вообще, но можно получить код таким образом, аналогично передавая данные вне диапазона с помощью любого из доступных эквивалентов another_program | bash -s 'value for $1' 'value for $2' - person Charles Duffy; 09.06.2020
comment
Даже если вы используете язык, который не предоставляет ничего, кроме system(), вы можете использовать setenv() для хранения литеральных значений в качестве переменных среды, а затем передавать код как константу, которая ссылается на эти переменные из тела. - person Charles Duffy; 09.06.2020
comment
The pipe-to-bash pattern simply shouldn't be followed at all -- возможно, вы правы. Вот о чем мой ответ. Я предполагаю, что это может быть неправильно в том смысле, что я должен дать больше предупреждений о предпочтительном подходе. Лично я использовал его для печати CLI-инструкции, которую пользователь может скопировать и вставить в терминал (опять-таки то, что вам никогда не следует поощрять, честно говоря). - person VasiliNovikov; 10.06.2020