Shell 编写如何在变量中传递带空格的参数的脚本

Shell Script how to pass an argument with spaces inside a variable

我正在制作一个脚本,通过 ssh 将目录与 rsync 同步。当我想定义一个自定义端口时,我遇到了麻烦。假设一个正常的工作脚本有一个语法:

#! /bin/sh

rval=2222
port="ssh -p $rval"

rsync --progress -av -e "$port" sflash@192.168.10.107:/home/sflash/Documents/tmp/tcopy/ /home/sflash/Documents/tmp/tcopy

公开自定义端口时的语法是 -e "ssh -p 2222"。但是,如果我想在这种情况下使用变量,例如:

#! /bin/sh

rval=2222
port="-e \"ssh -p $rval\""

rsync --progress -av $port sflash@192.168.10.107:/home/sflash/Documents/tmp/tcopy/ /home/sflash/Documents/tmp/tcopy

由于与 IFS 的某种交互,这可能无法正常工作。如果我引入一个 if 语句来检查 port 是否被定义,我可以完全避免这种情况,但我很好奇失败的确切原因以及是否存在强制实现此方法的解决方案。

编辑:抱歉,我仅限于 posix shell

您实际上没有提供足够的细节来确定,但我怀疑您遇到了一个常见的误解。

当你这样做时:

rval=2222
rsync --progress -av -e "ssh -p $rval" src dst

rsync 使用 6 个参数调用:--progress-av-essh -p 2222srcdst.

另一方面,当您这样做时:

port="-e \"ssh -p $rval\""
rsync --progress -av $port src dst

rsync 使用 8 个参数调用:--progress-av-e"ssh-p2222"srcdst

您不希望将双引号传递给 rsync,并且您不希望将 ssh -p 2222 拆分为 3 个参数。一种(糟糕的)方法来做你想做的事是使用 eval。但看来你真正想要的是:

rval=2222
port="ssh -p $rval"
rsync --progress -av ${port:+-e "$port"} src dst

现在,如果端口已定义而不是空字符串,则将使用附加参数 -essh -p 2222(根据需要)调用 rsync,如果端口未定义或为空,-e$port 参数都不会被使用。

请注意,在这种情况下,您不能在 ${port:+-e "$port"} 周围使用双引号。如果这样做,那么当 $port 是空字符串时,空字符串将作为参数传递。当 $port 不是空字符串时,它将传递单个参数 -e ssh -p 2222 而不是拆分为 2 个参数 -essh -p 2222.