Как построить команду bash и аргументы для ssh / su -c

Существуют инструменты Python

$pip install humanfriendly  # Also available as a --user install in ~/.local/bin

$humanfriendly --format-size=2048
2.05 KB
$humanfriendly --format-number=2048
2,048

Я не вижу --двоичного флага :(, поэтому вам придется использовать Python напрямую для двоичного представления:

$python -c 'import sys, humanfriendly; print(humanfriendly.format_size(int(sys.argv[1]), binary=True))' 2048
2 KiB
$python -c 'import sys, humanfriendly; print(humanfriendly.format_size(int(sys.argv[1]), binary=True))' 2000
1.95 KiB
1
07.09.2020, 10:14
2 ответа

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

backupcommand="rsync -ar \"${a[@]}\" dest/"
0
18.03.2021, 23:06

Сначала нам нужен способ показать, что у нас есть в нашем массиве bash, sources. Кажется, хорошим способом является использование printf '%s\n' <args>, который будет выводить по одной строке для каждого аргумента в <args>.

Например:

$ sources=( file1 file2 "other stuff" )
$ printf '%s' "${sources[@]}"
file1
file2
other stuff

Если мы используем эту команду в качестве backupcommand, мы можем увидеть, что программа резервного копирования (, например.rsync)фактически получит в качестве своих аргументов. Предположим, что команда, которую мы хотим запустить черезbash -c...(или ssh...), это printf '%s\n' <args>и что у нас есть два аргумента, file1и other stuff.

Мы хотим запустить эту команду в целевой оболочке:

$ printf '%s\n' file1 other\ stuff
file1
other stuff

Итак, чтобы получить это как один аргумент, нам нужно процитировать его. Мы можем использовать "", ''или \для цитирования. Мы можем снова использовать printf '%s\n', чтобы убедиться, что мы сделали это успешно...

$ # With backslashes:
$ printf '%s\n' printf\ \'%s\\n\'\ file1\ other\\\ stuff
printf '%s\n' file1 other\ stuff

$ # With single quotes
$ printf '%s\n' 'printf '\''%s\n'\'' file1 other\ stuff'
printf '%s\n' file1 other\ stuff

$ # Using a variable to store the command...
$ the_command='printf '\''%s\n'\'' file1 other\ stuff'
$ #..then using that variable as a single argument...
$ printf '%s\n' "$the_command"
printf '%s\n' file1 other\ stuff

Пока все хорошо. В последней версии мы указали переменную, содержащую команду.

Теперь мы можем использовать массив для аргументов? Что нам нужно сделать, так это заключить в кавычки/экранировать каждый элемент массива и добавить его к одной строке the_command.

${var[@]}указывает bash создавать один токен для каждого элемента массива. Но они не экранированы, потому что они уже были интерпретированы. Поэтому мы не можем просто добавить это в командную строку оболочки. Итак, нам нужен способ применения цитирования.

Баш имеет printf '%q' arg, чтобы процитировать arg. Мы можем использовать подстановку команд$(...)

$ sources=( file1 other\ stuff )
$ the_command=printf\ \'%s\\n\'
$ for item in "${sources[@]}"
  do the_command="$the_command "$(printf '%q' "$item")
  done
$ printf '%s\n' "$the_command"
printf '%s\n' file1 other\ stuff

Ура! Однако,мы можем почистить это примерно так:

$ sources=( file1 other\ stuff )
$ the_command="printf '%s\\n'"$(printf ' %q' "${sources[@]}")
$ printf '%s\n' "$the_command"
printf '%s\n' file1 other\ stuff

$ # And as final proof...
$ bash -c "$the_command"
file1
other stuff

Применительно к исходной задаче:

sources=( file1 file2 "other stuff" )
backupcommand="rsync -ar "$(printf ' %q' "${sources[@]}")" dest/"
su backupuser -c "$backupcommand"

Резюме

  • printf '%q' argцитатыarg
  • подстановка команды $(...)создает один маркер из вывода команды.
  • доступны различные методы цитирования/экранирования; выбери самую читаемую!
1
18.03.2021, 23:06

Теги

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