期望脚本中的 rsync 路径
rsync-path in expect script
我写了一个备份脚本,使用 expect
来自动化 rsync
。
为确保备份所有文件,我使用了 rsync
的 --rsync-path="sudo rsync"
选项。
#!/bin/bash
set -e
expect <<- DONE
spawn rsync --rsync-path="sudo\ rsync" -uav myuser@example.com:/home/myuser/ /backups/home/myuser
expect ":"
send -- "mypassword\r"
expect eof
DONE
这没有按预期工作。我收到以下错误消息:
bash: sudo rsync: command not found
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.1]
我已经看到 similar questions 关于在 rsync
命令行中使用空格,并在各处添加了单引号、双引号和转义反斜杠,但还没有任何效果。
如何在 expect
脚本中使用“--rsync-path
with spaces”?
你不能使用 --rsync-path
来做到这一点,因为你想要的是 word-splitting,即 shell 确实如此。
那么如何通过指定单个路径名 运行 一个命令来 运行 一个命令?
在远程系统上,编写脚本包装器 susync
执行 sudo
(不要忘记 chmod 755
):
#!/bin/sh
exec /path/to/sudo /path/to/rsync "$@"
并使用
spawn rsync --rsync-path=/path/to/susync ...
问题是你有这个:
--rsync-path="sudo\ rsync"
在 Expect/Tcl 中,这被视为:
--rsync-path="sudo rsync"
而且,因为 Tcl 的引用规则 与 bash 的不同,所以使用 "sudo rsync"
加倍quotes 作为发送到远程端的命令。这让事情变得非常混乱。正确的解决方法是省略双引号; (backslash-quoted) 反斜杠将确保它全部作为一个参数进入 spawn,并正确发送到另一端。
我真的不喜欢将 HEREdocs 与 Tcl 一起使用。当不同类型的引用相互作用时,太多的事情会变得奇怪。在真正的目标语言中使用单个脚本要好得多,因为这样你就可以使用变量使事情变得更清楚:
#!/usr/bin/env expect
set remoteRsync "sudo rsync"
set from myuser@example.com:/home/myuser/
set to /backups/home/myuser
set pass "mypassword"
spawn rsync --rsync-path=$remoteRsync -uav $from $to
expect ":"
send -- "$pass\r"
expect eof
exit
这使得代码结构更易于查看,也更易于调试。开头带有 /usr/bin/env
的位只是避免使用 bash 包装器的一种方法。
不,这些变量在使用时不需要引用。 Tcl 不是 bash.
我写了一个备份脚本,使用 expect
来自动化 rsync
。
为确保备份所有文件,我使用了 rsync
的 --rsync-path="sudo rsync"
选项。
#!/bin/bash
set -e
expect <<- DONE
spawn rsync --rsync-path="sudo\ rsync" -uav myuser@example.com:/home/myuser/ /backups/home/myuser
expect ":"
send -- "mypassword\r"
expect eof
DONE
这没有按预期工作。我收到以下错误消息:
bash: sudo rsync: command not found
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.1]
我已经看到 similar questions 关于在 rsync
命令行中使用空格,并在各处添加了单引号、双引号和转义反斜杠,但还没有任何效果。
如何在 expect
脚本中使用“--rsync-path
with spaces”?
你不能使用 --rsync-path
来做到这一点,因为你想要的是 word-splitting,即 shell 确实如此。
那么如何通过指定单个路径名 运行 一个命令来 运行 一个命令?
在远程系统上,编写脚本包装器 susync
执行 sudo
(不要忘记 chmod 755
):
#!/bin/sh
exec /path/to/sudo /path/to/rsync "$@"
并使用
spawn rsync --rsync-path=/path/to/susync ...
问题是你有这个:
--rsync-path="sudo\ rsync"
在 Expect/Tcl 中,这被视为:
--rsync-path="sudo rsync"
而且,因为 Tcl 的引用规则 与 bash 的不同,所以使用 "sudo rsync"
加倍quotes 作为发送到远程端的命令。这让事情变得非常混乱。正确的解决方法是省略双引号; (backslash-quoted) 反斜杠将确保它全部作为一个参数进入 spawn,并正确发送到另一端。
我真的不喜欢将 HEREdocs 与 Tcl 一起使用。当不同类型的引用相互作用时,太多的事情会变得奇怪。在真正的目标语言中使用单个脚本要好得多,因为这样你就可以使用变量使事情变得更清楚:
#!/usr/bin/env expect
set remoteRsync "sudo rsync"
set from myuser@example.com:/home/myuser/
set to /backups/home/myuser
set pass "mypassword"
spawn rsync --rsync-path=$remoteRsync -uav $from $to
expect ":"
send -- "$pass\r"
expect eof
exit
这使得代码结构更易于查看,也更易于调试。开头带有 /usr/bin/env
的位只是避免使用 bash 包装器的一种方法。
不,这些变量在使用时不需要引用。 Tcl 不是 bash.