Как я могу сгенерировать аргументы для другой команды с помощью подстановки команд

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

Из вывода pvdisplay видно, что / dev / sdd1 на 100% свободен, так что, похоже, это новый диск.

11
22.01.2019, 02:45
3 ответа

I wrote a script which can generate those arguments for me, with quotes

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

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

Если ./gen_args.shвыдает результат, аналогичный 'foo bar' '*' asdf, то мы можем запустить eval "args=( $(./gen_args.sh) )"для заполнения массива с именем argsрезультатами. Это будут три элемента foo bar, *, asdf.

Как обычно, мы можем использовать "${args[@]}"для расширения элементов массива по отдельности:

$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:\n" "$var"; done
:foo bar:
:*:
:asdf:

(Обратите внимание на кавычки. "${array[@]}"расширяется на все элементы как отдельные аргументы без изменений. Без кавычек элементы массива подлежат разбиению на слова. См., например. страница Arrays в BashGuide .)

Однако , evalбудут успешно запускать любые подстановки оболочки, поэтому $HOMEв выводе будет расширяться до вашего домашнего каталога, а подстановка команд фактически запустит команду в оболочке, работающей eval. Вывод "$(date >&2)"создаст один пустой элемент массива и выведет текущую дату на стандартный вывод. Это вызывает беспокойство, если gen_args.shполучает данные из какого-либо ненадежного источника, например, другого хоста в сети, имена файлов, созданные другими пользователями. Вывод может включать произвольные команды.(Если бы сам get_args.shбыл вредоносным, ему не нужно было бы ничего выводить, он мог бы просто запускать вредоносные команды напрямую.)


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

Давайте выберем #и получим вывод сценария foo bar#*#asdf. Теперь мы можем использовать расширение команды без кавычек , чтобы разделить вывод команды на аргументы.

$ IFS='#'                          # split on '#' signs
$ set -f                           # disable globbing
$ args=( $(./gen_args3.sh ) )     # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:\n" "$var"; done
:foo bar:
:*:
:asdf:

Вам нужно будет снова установить IFSпозже, если вы зависите от разделения слов в другом месте скрипта(unset IFSдолжно работать, чтобы сделать его значением по умолчанию ), а также использовать set +f, если вы хотите использовать подстановку позже.

Если вы не используете Bash или другую оболочку с массивами, вы можете использовать для этого позиционные параметры. Замените args=( $(...) )на set -- $(./gen_args.sh)и используйте "$@"вместо "${args[@]}". (Здесь тоже нужны кавычки вокруг "$@", иначе позиционные параметры подлежат разбиению на слова.)

10
27.01.2020, 19:57

Проблема в том, что после того, как ваш somecommandскрипт выводит параметры для othercommand, эти параметры на самом деле являются просто текстом и зависят от стандартного синтаксического анализа оболочки (, на который влияет то, что $IFSпроисходит и что действуют параметры оболочки, которыми вы в общем случае не управляете ).

Вместо использования с somecommandпо для вывода опций было бы проще, безопаснее и надежнее использовать его для вызоваothercommand. Скрипт somecommandтогда будет скриптом-оболочкой вокруг othercommandвместо какого-то вспомогательного скрипта, который вам нужно будет не забыть вызывать каким-то особым образом как часть командной строки otherscript. Сценарии-оболочки — очень распространенный способ предоставления инструмента, который просто вызывает другой подобный инструмент с другим набором параметров (, просто проверьте с помощью file, какие команды в /usr/binна самом деле являются оболочками сценариев оболочки ).

В bash, kshили zshвы можете легко создать сценарий-оболочку, который использует массив для хранения отдельных параметров для othercommand, например:

options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" )  # add additional option

Затем вызовитеothercommand(внутри скрипта-оболочки):

othercommand "${options[@]}"

Расширение "${options[@]}"гарантирует, что каждый элемент массива optionsбудет отдельно заключен в кавычки и представлен в othercommandкак отдельные аргументы.

Пользователь оболочки не заметит тот факт, что она на самом деле вызывает othercommand, что было бы не истинным, если бы сценарий вместо этого просто генерировал параметры командной строки для othercommandв качестве вывода..

В /bin/shиспользуйте $@для сохранения опций:

set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!"  # add additional option

othercommand "$@"

(set— это команда, используемая для установки позиционных параметров $1, $2, $3и т. д. Это то, что составляет массив $@в стандартной оболочке POSIX. Начальный --должен сигнализировать set, что не задано никаких опций, только аргументы. --на самом деле требуется только в том случае, если первое значение начинается с-).

Обратите внимание, что двойные кавычки вокруг $@и ${options[@]}гарантируют, что элементы не будут разделены на отдельные слова -(и имена файлов ).

6
27.01.2020, 19:57

Если вывод somecommandимеет надежный синтаксис оболочки, вы можете использоватьeval:

$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello 
hi and bye

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

$ cat test.sh 
for var in "$@"
do
    echo "|$var|"
done
$ ls
bar  baz  test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh

Обратите внимание, что echo rm bar baz test.shне было передано сценарию (из-за;)и выполнялось как отдельная команда. Я добавил |вокруг $var, чтобы выделить это.


Как правило, если вы не можете полностью доверять выходным данным somecommand, невозможно надежно использовать их выходные данные для построения командной строки.

4
27.01.2020, 19:57

Теги

Похожие вопросы