我正在尝试以下操作:
❯ ssh user1@10.8.1.1 zsh --version
zsh 5.8.1 (x86_64-apple-darwin22.0)
❯ ssh user1@10.8.1.1 zsh -lc "for ((index=1; index <= 1; index++)); do echo \$index; done"
zsh:1: parse error near `)'
然而,在本地,也没有zsh -lc
通过ssh,它的工作原理是:
❯ zsh -lc "for ((index=1; index <= 1; index++)); do echo $index; done"
1
❯ ssh user1@10.8.1.1 "for ((index=1; index <= 1; index++)); do echo \$index; done"
1
当我在for循环之前做任何事情时,我也可以让它工作:
❯ ssh user1@10.8.1.1 zsh -lc "echo 1; for ((index=1; index <= 1; index++)); do echo \$index; done"
1
有什么建议我该去哪里找吗?
2条答案
按热度按时间pb3s4cty1#
ssh只向远程shell传递一个字符串。不是单个参数的列表--一个字符串。当你传递多个参数时,它只是用空格将它们连接起来以生成该字符串;因此,当您自己生成一个字符串时(将
zsh
和-lc
都作为该字符串的一部分),它可以更容易地考虑这一点,从而得到正确的结果。下面的两种方法都避免了手动转义的需要:作为一个人,你永远不会知道你需要将
$index
更改为\$index
,或者决定如何重新转义它以通过额外的shell(无论是本地的还是远程的)。确保 * 只有 * zsh可以看到/解析/munge你传递的代码
如果你不知道默认的远程shell是什么,并且你正在运行的代码没有从stdin读取,理想的方法是在stdin上传递代码,这样它就只在zsh的远程副本启动之后才通过线路:
这样,您还可以使用
$(declare -p varname)
通过网络传递局部变量,并确保它们的值由zsh* 解析,而不需要任何其他shell。如果远程shell足够兼容,则可以使用一个保持stdin清晰的回退
如果远程shell是带有ksh扩展的任何东西--不仅仅是zsh,还有bash &c --这都可以正常工作,但如果
printf %q
使用$'\t'
或$'\n'
语法转义制表符或换行符,则可能会失败。解释错误所在
当你跑的时候...
首先,引号被 * 本地 * 删除,然后ssh连接参数生成一个字符串传递给远程shell,所以我们得到:
在这里,只有
for
作为-c
的参数给出;接下来,我们有后续的命令进入zsh
的argv,然后是shell语法,远程shell会感到困惑/惊讶。falq053o2#
还有一个你想避免的目标shell的单词分割。所以再次引用应该可以: