我有一个简短的脚本,用于scp
将文件复制到许多远程主机(是的,我知道rdist
和rsync
;它们都无法为一些主机工作 - 这不是这里的重点;我只是复制一些非-无论如何都是关键文件)。
脚本的内容看起来像这样:
for h in $HOSTS; do
echo $h
echo '----------------------------------------'
scp -r $FILES ${h}:
echo ''
done
以下是运行此脚本的部分输出:
protector
----------------------------------------
.bash_profile 100% 555 0.5KB/s 00:00
.bashrc 100% 2124 2.1KB/s 00:00
.zshenv 100% 561 0.6KB/s 00:00
.zshrc 100% 2354 2.3KB/s 00:00
.shrc 100% 1887 1.8KB/s 00:00
.bash_logout 100% 17 0.0KB/s 00:00
.logout 100% 64 0.1KB/s 00:00
.zlogout 100% 17 0.0KB/s 00:00
.vimrc 100% 717 0.7KB/s 00:00
pup
----------------------------------------
.bash_profile 100% 555 0.5KB/s 00:00
.bashrc 100% 2124 2.1KB/s 00:00
.zshenv 100% 561 0.6KB/s 00:00
.zshrc 100% 2354 2.3KB/s 00:00
.shrc 100% 1887 1.8KB/s 00:00
.bash_logout 100% 17 0.0KB/s 00:00
.logout 100% 64 0.1KB/s 00:00
.zlogout 100% 17 0.0KB/s 00:00
.vimrc 100% 717 0.7KB/s 00:00
由于这个脚本复制到数百台主机,需要一点时间,所以我决定尝试使用GNU 并行以加快速度。这是使用的脚本的修订版本parallel
(请不要在开始时评论echo
hack,它与问题无关):
(for host in $(echo $HOSTS); do echo $host; done) | parallel "echo {}; echo '----------------------------------------' ; scp -r $FILES {}: ; echo ''"
问题是,以这种方式使用的输出scp
如下所示:
pup
----------------------------------------
soils
----------------------------------------
因为命令是并行运行的,所以顺序不同,并行似乎比 scps 的 for 循环完成得快得多,但正如您所看到的,scp 没有输出到 stdout。我不明白为什么 - 例如,从 echo 到标准输出的输出没有被抑制。当我尝试scp -v
内部并行时,我得到部分详细输出,但我没有得到任何通常的大小/时间信息。
有人知道为什么 scp 输出被抑制吗?
答案1
要欺骗scp
认为它已tty
连接,您可以使用script
:
script -c 'scp foo server1:/bar/'
因此,要运行它,parallel
您需要类似的东西:
parallel -j30 "echo {}; echo '----------------------------------------' ; script -c 'scp -r $FILES {}:' ; echo ''" ::: $HOSTS
要了解更多信息,请观看介绍视频(https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1),示例 (n1_argument_appending">http://www.gnu.org/software/parallel/man.html#example__working_as_xargs_n1_argument_appending)和教程(http://www.gnu.org/software/parallel/parallel_tutorial.html)。
答案2
这似乎对我有用:
#!/bin/sh
for h in $(cat /tmp/servers);
do
for f in $(cat /tmp/files);
do
echo $h
echo '----------------------'
parallel -vv "scp root@$h:$f /tmp"
done
done
取出 -vv 以删除详细输出。当然,对其进行修改,以便 A) 它使用您的 $HOSTS 和 $FILES 变量,B) 它复制到远程服务器而不是从远程服务器复制。