可选择在 bash 脚本中传递一个参数

Optionally pass an argument in a bash script

我想在使用 rsync 时使用自定义身份文件,但前提是该文件存在,否则我不想为 rsync 使用自定义 ssh 命令。我在引用时遇到问题。查看示例。

如果身份文件存在则需要命令

rsync -e "ssh -i '/tmp/id_rsa'" /tmp/dir/ u@h:/tmp/dir

身份文件不存在时需要的命令

rsync /tmp/dir/ u@h:/tmp/dir

我想创建一个包含 -e "ssh -i '/tmp/id_rsa'" 的变量并按如下方式使用它

rsync ${identityArg} /tmp/dir/ u@h:/tmp/dir

此变量可以为空或包含所需的 ssh 命令。

我填充变量的一个例子(我试过很多方法)

IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
  identityArg="-e 'ssh -i \"${IDENTITY_FILE}\"'"
fi

问题是命令中的引号总是错误的,我最终得到了与这些类似的命令(set -x 在脚本中设置,这是输出)

rsync -e '\ssh' -i '"/tmp/id_rsa"'\''' /tmp/dir/ u@h:/tmp/dir

关于 bash 中的引用,我有一些不明白的地方。如果您有任何关于在 bash 脚本中使用单引号和双引号的好资源,我想阅读它。

您想添加两个位置参数:-essh -i '/tmp/id_rsa',其中 /tmp/id_rsa 是扩展变量。你应该为此使用一个数组:

args=(/tmp/dir/ u@h:/tmp/dir)
idfile=/tmp/id_rsa

# Let [[ ... ]] do the quoting
if [[ -f $idfile ]]; then
    # Prepend two parameters to args array
    args=(-e "ssh -i '$idfile'" "${args[@]}")
fi

rsync "${args[@]}"

我不相信内部单引号对于 ssh -i 是必要的,但这扩展到问题中显示的命令。

这样试试

id=/tmp/id_rsa
[[ -e $id ]] && o1='-e' o2="ssh -i '$id'"
echo $o1 "$o2" /tmp/dir/ u@h:/tmp/dir

尝试正确转义引号很棘手。最好尝试利用现有结构。很少有选择,视情况而定

如果身份文件的名称仅包含简单字符(无空格、通配符等),请考虑不要将其括在引号中。在这种情况下,您可以

IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
  identityArg="-e 'ssh -i ${IDENTITY_FILE}'"
fi
...
rsync $identityArg ...

另一种选择是始终传递命令(ssh 或 'ssh -I ...')。这将自动处理身份文件中的特殊字符。

IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
  identityArg="-i '${IDENTITY_FILE}'"
fi
rsync -e "ssh $identityArg" ...

第三种选择是使用数组创建 rsync 的参数,并让 shell 根据需要转义字符。这将允许身份文件中的任何字符。

IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
  identityArg=(-e "ssh -i '${IDENTITY_FILE}'")
fi
rsync "${identityArg[@]}" ...