我想使用本地 shell 在两个远程主机之间传输文件,但似乎 rsync 不支持在指定两个远程主机时进行同步,如下所示:
$ rsync -vuar host1:/var/www host2:/var/www
The source and destination cannot both be remote.
有没有其他的方法/命令可以用来达到类似的结果呢?
rsync -vuar host1:/var/www host2:/var/www
ssh -R localhost:50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /var/www localhost:/var/www'
第一个实例的/var/www
适用于host1
上的源,localhost:/var/www
对应于host2
上的目标。
如果你好奇的话,-R
选项在host1
上设置了一个反向通道,将端口50000(通过你的本地机器)映射到host2
上的端口22。没有直接连接从host1
到host2
。
~/.ssh/config
,但由于远程主机被映射为端口50000上的 localhost
,它可能与您的配置不匹配。 - roaima~/.ssh/config
文件。 - roaimascp -3
进行间接连接。 - Cedric Knighthost1
到host2
的直接连接。这样做的好处是运行该命令的机器不会成为传输的瓶颈。ssh -A host1 rsync -vuar /var/www host2:/var/www
-D
而不是-A
来绕过网络限制而不是密钥限制);解释了优势;命令简短且实际可行。请注意,如果username@host1
与本地用户名不同,您可能需要指定它。此外,当连接到host2时,rsync会执行主机密钥验证,因此host1的密钥应该已经存在于host2上的~/.ssh/known_hosts文件中,否则命令将失败。 - Cedric Knightssh -A
之前,您必须在构建配置中添加名为“SSH代理”的“构建特性”,请参阅https://confluence.jetbrains.com/display/TCD10/SSH+Agent)。 - John Zwinckssh-add
将我的ssh密钥添加到SSH Agent中。 - Matthiasssh -A host1 sudo rsync -vuar /var/www host2:/var/www
是无效的。 - Eric Hansenrsync -vuar host1:/host1/path host2:/host2/path
ssh -R 50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path'
localhost$ ssh -v -R 50000:host2:22 host1
host1$ rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path
rsync
在 host1 上启动,并将目标设置为 host2。(你可以在评论中要求澄清。) - roaimaSOURCE_USER=user1
SOURCE_HOST=hostname1
SOURCE_PATH=path1
TARGET_USER=user2
TARGET_HOST=host2
TARGET_PATH=path2
ssh -l $TARGET_USER -A -R localhost:22000:$TARGET_HOST:22 \
$SOURCE_USER@$SOURCE_HOST "rsync -e 'ssh -p 22000' -vuar $SOURCE_PATH \
$TARGET_USER@localhost:$TARGET_PATH"
-R
选项从本地主机连接到主机1,同时设置端口转发,允许主机1通过本地主机连接到主机2(-R localhost:$FREE_PORT:$TARGET_ADDR_PORT
)-A
选项,方便进行第二个ssh通道的身份验证这真是复杂!有没有更简单的方法?
当从源地址复制所有或大部分字节到目标地址时,使用tar
要简单得多:
ssh $SOURCE_HOST "tar czf - $SOURCE_PATH" \
| ssh $TARGET_HOST "tar xzf - -C $TARGET_PATH/"
剧本
#!/bin/bash
#-------------------SET EVERYTHING BELOW-------------------
# whatever you type after ssh to connect to SOURCE/TARGE host
# (e.g. 1.2.3.4:22, user@host:22000, ssh_config_alias, etc)
# So if you use "ssh foo" to connect to SOURCE then
# you must set SOURCE_HOST=foo
SOURCE_HOST=host1
TARGET_HOST=host2
# The IP address or hostname and ssh port of TARGET AS SEEN FROM LOCALHOST
# So if ssh -p 5678 someuser@1.2.3.4 will connect you to TARGET then
# you must set TARGET_ADDR_PORT=1.2.3.4:5678 and
# you must set TARGET_USER=someuser
TARGET_ADDR_PORT=1.2.3.4:5678
TARGET_USER=someuser
SOURCE_PATH=/mnt/foo # Path to rsync FROM
TARGET_PATH=/mnt/bar # Path to rsync TO
RSYNC_OPTS="-av --bwlimit=14M --progress" # rsync options
FREE_PORT=54321 # just a free TCP port on localhost
#---------------------------------------------------------
echo -n "Test: ssh to $TARGET_HOST: "
ssh $TARGET_HOST echo PASSED| grep PASSED || exit 2
echo -n "Test: ssh to $SOURCE_HOST: "
ssh $SOURCE_HOST echo PASSED| grep PASSED || exit 3
echo -n "Verifying path in $SOURCE_HOST "
ssh $SOURCE_HOST stat $SOURCE_PATH | grep "File:" || exit 5
echo -n "Verifying path in $TARGET_HOST "
ssh $TARGET_HOST stat $TARGET_PATH | grep "File:" || exit 5
echo "configuring ssh from $SOURCE_HOST to $TARGET_HOST via locahost"
ssh $SOURCE_HOST "echo \"Host tmpsshrs; ControlMaster auto; ControlPath /tmp/%u_%r@%h:%p; hostname localhost; port $FREE_PORT; user $TARGET_USER\" | tr ';' '\n' > /tmp/tmpsshrs"
# The ssh options that will setup the tunnel
TUNNEL="-R localhost:$FREE_PORT:$TARGET_ADDR_PORT"
echo
echo -n "Test: ssh to $SOURCE_HOST then to $TARGET_HOST: "
if ! ssh -A $TUNNEL $SOURCE_HOST "ssh -A -F /tmp/tmpsshrs tmpsshrs echo PASSED" | grep PASSED ; then
echo
echo "Direct authentication failed, will use plan #B:"
echo "Please open another terminal, execute the following command"
echo "and leave the session running until rsync finishes"
echo "(if you're asked for password use the one for $TARGET_USER@$TARGET_HOST)"
echo " ssh -t -A $TUNNEL $SOURCE_HOST ssh -F /tmp/tmpsshrs tmpsshrs"
read -p "Press [Enter] when done..."
fi
echo "Starting rsync"
ssh -A $TUNNEL $SOURCE_HOST "rsync -e 'ssh -F /tmp/tmpsshrs' $RSYNC_OPTS $SOURCE_PATH tmpsshrs:$TARGET_PATH"
echo
echo "Cleaning up"
ssh $SOURCE_HOST "rm /tmp/tmpsshrs"
tar
是一个很好的选择。另一方面,rsync
可以处理重新启动和增量传输。 - roaimarsync
。但如果您不想在远程服务器上运行脚本,可以在本地系统上运行一个脚本,通过ssh执行rsync命令。ssh user@$host1 <<ENDSSH >> /tmp/rsync.out 2>&1
rsync -vuar /var/www host2:/var/www
ENDSSH
此外,正如你可能已经了解的那样,rsync只进行单向同步。如果你想要双向同步,可以看看osync(https://github.com/deajan/osync)。我使用过它并发现它非常有帮助。
SRC=user@source-server:/some/path/in/source/* && \
DST=user@destin-server:/some/path/in/destin/* && \
TMP=/tmp/rsync && \
rm -fr $TMP && \
mkdir -p $TMP && \
rsync -av $SRC $TMP && \
rsync -av $TMP/* $DST/ && \
rm -fr $TMP
(){ local RSYNC_TMP=$(mktemp); rsync -aP src-host:~/filename $RSYNC_TMP; rsync -aP $RSYNC_TMP dest-host:~/filename; rm -rf $RSYNC_TMP }
这可以复制/粘贴到zsh中,因此如果您的主机是macOS,则非常适用。然而,这不会保护所涉及的文件的安全性。将文件名替换为目录名,并将local RSYNC_TMP=$(mktemp)
更改为local RSYNC_TMP=$(mktemp -d)
应允许进行目录传输。
对于更安全的临时传输机制,假设您的主机是Linux,我倾向于使用[bwrap(1)][1]
或类似工具来创建仅在进程持续时间内存在的tmpfs挂载。
$ mkdir host1 host2
$ sshfs user1@host1:/path1 ./host1
$ sshfs user2@host2:/path2 ./host2
$ rsync -a ./host1/ ./host2/
$ mkdir host1
$ rsync -a user1@host1:/path1/ ./host1/
$ rsync -a ./host1/ user2@host2:/path2/
sshfs
是我所来自的路径。不幸的是,sshfs
无法处理源文件中的硬链接,因此请注意要复制哪些数据到它上面。 - Paul w. Muad'dib
sshfs
的缺点是,rsync
将源文件系统和目标文件系统都视为本地文件系统,因此禁用了其增量算法。此时,您几乎可以使用cp -p
。请参阅提出此建议的答案及其后续评论。 - roaimascp -3 A:file C:file
。详情请参考:https://superuser.com/a/401245/264813。 - Ciprian Tomoiagă