首页 > 解决方案 > Shell脚本如何在变量内传递带有空格的参数

问题描述

我正在制作一个脚本来通过 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

标签: sh

解决方案


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

当你这样做时:

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, -p, 2222", src, 和dst.

您不希望将双引号传递给rsync,也不希望ssh -p 2222将 拆分为 3 个参数。做你想做的事情的一种(可怕的)方法是使用eval. 但似乎你真正想要的是:

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

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

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


推荐阅读