如何为 ssh / su -c 构建 bash 命令和参数

如何为 ssh / su -c 构建 bash 命令和参数

我正在从源数组列表中备份内容,有点像这个简化版本:

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

问题是$backupcommand用正确的转义创建的。上面的意思是 rsync 查找一个名为“other”的文件和另一个名为“stuff”的文件,而不是一个名为“other stuff”的文件

我怎样才能构造一个引用的命令sh -c ...(或ssh ...等等)。我正在使用 bash。

答案1

首先,我们需要一种方法来显示 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>,并且我们有两个参数file1other stuff

我们要在目标 shell 上运行此命令:

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

因此,为了将其作为一个论点,我们需要引用它。我们可以使用""or''\来引用。我们可以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 为每个数组项生成一个标记。但这些并没有被转义,因为它们已经被解释了。所以我们不能只是将其放入 shell 命令字符串中。所以我们需要一种应用引用的方法。

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
  • 命令替换$(...)根据命令的输出创建单个标记。
  • 可以使用各种引用/转义方法;选择最可读的一个!

答案2

尝试在数组周围添加转义引号,如下所示

backupcommand="rsync -ar \"${a[@]}\" dest/"

相关内容