如何正确替换脚本中包含空格的字符串

如何正确替换脚本中包含空格的字符串

在我的脚本中我有:

sshkey="/Users/me/some path/with spaces/id_rsa"
dstport=...
dstparent=...
dstuserhost=...

rsync -az --delete -e "ssh -i $sshkey -p $dstport" $src $dstuserhost:$dstparent

当我运行它时,我得到:

rsync:link_stat“/Users/me/some”失败:没有这样的文件或目录(2)

答案1

只需在周围添加单引号$sshkey即可解决该问题:

rsync -az --delete -e "ssh -i '$sshkey' -p '$dstport'" "$src" "$dstuserhost:$dstparent"

$sshkey值将在调用之前由交互式 shell 扩展,因为它位于双引号字符串内,但单引号会阻止在调用设置连接rsync时进一步拆分字符串。rsyncssh

假设$sshkey本身不包含单引号字符。

答案2

您需要注入一些“内部”引号。我会说

printf -v rsh_cmd 'ssh -i "%s" -d "%s"' "$sshkey" "$dstport"
...
rsync ... -e "$rsh_cmd"

答案3

-e该选项的参数rsync不是 shell 命令行,而是rsync命令行。rsync使用与 Bourne shell 不同的自己的规则来解析它。

与所有 shell 一样,它将空格字符视为参数分隔符,并且与 Bourne shell 一样,它将单引号和双引号(但不包括反斜杠)视为引用运算符。它不执行任何 shell 扩展(如$var$(cmd)*.txt~user...)。

因此,要在该伪命令行中嵌入任意参数,您可以将其括在双引号中,但双引号字符本身除外(然后将其括在单引号中),或者将它们括在单引号中,但单引号字符本身除外(然后用双引号括起来)。

例如,如果您的 ssh 密钥文件是/cygdrive/c/John Doe/.ssh/John "Dude" Doe's.rsa,则 的参数-e应该类似于'/cygdrive/c/John Doe/.ssh/John "Dude" Doe'"'"'s.rsa'"/cygdrive/c/John Doe/.ssh/John "'"'"Dude"'"'" Doe's.rsa"

您可以定义一个专用函数来执行此操作rsync 引用喜欢:

# ksh93/bash/zsh syntax:
rsync_quote() {
  local arg="$1"
  arg=${arg//\'/\'\"\'\"\'}
  printf "'%s'\n" "$var"
}

rsync -e "ssh -i $(rsync_quote "$sshkey") -p $dstport" ...

另一种选择是将 shell 作为参数传递给 shell,-e然后解释ssh命令行。这样做的一个优点是 shell 可以进行变量扩展。

KEY=$sshkey PORT=$dstport SSH_COMMAND='ssh -i "$KEY" -p "$PORT" "$@"' \
  rsync -e "sh -c 'eval \"\$SSH_COMMAND\"' sh" ...

如果您使用 运行它strace -fe execve -s 999,您会看到它展开:

execve("/usr/bin/rsync", ["rsync", "-e", "sh -c 'eval \"$SSH_COMMAND\"' sh", "1/", "localhost:2/"], 0x7ffc03b83678 /* 74 vars */) = 0
strace: Process 7208 attached
[pid  7208] execve("/bin/sh", ["sh", "-c", "eval \"$SSH_COMMAND\"", "sh", "localhost", "rsync", "--server", "-e.LsfxC", ".", "2/"], 0x7ffcc6ad0f28 /* 74 vars */) = 0
[pid  7209] execve("/usr/bin/ssh", ["ssh", "-i", "/cygdrive/c/John Doe/.ssh/John \"Dude\" Doe's.rsa", "-p", "2222", "localhost", "rsync", "--server", "-e.LsfxC", ".", "2/"], 0x5651a0c144a8 /* 74 vars */) = 0

相关内容