Este script irá copiar um número arbitrário de diretórios de entrada, para um número arbitrário de hosts, em paralelo através do uso de trabalhos em segundo plano do shell. Aqui eu usei cpio porque é fácil dividir e canalizar os arquivos de entrada, mas você pode modificar isso para usar rsync --files-from
também.
Uso: multi-cpio.sh <srcfile> <dstfile>
(requer ssh-keys para login não interativo)
srcfile
contém um diretório por linha, como:
/usr/share/man/man1
/usr/share/man/man3
/usr/share/man/man5
dstfile
contém um destino remoto por linha, como:
user@host:/tmp/a
user@host:/tmp/b
user@host:/tmp/c
... e a fonte para multi-cpio.sh
:
#!/bin/bash
SRCLIST=$1
DSTLIST=$2
# create temporary files, safely, in /tmp with mcpio prefix
TEMP='tempfile -p mcpio'
# loop over input file and create a list of all files to be copied
for I in 'cat $SRCLIST' ; do
find $I -depth -print >>$TEMP
done
# split the file into CPU count + factor
# set to '4' here, seems like ~6x CPIO will max my 1Gb Ethernet link to ~800Mbps in atop
SPLITCOUNT= $(( $( wc -l $TEMP | cut -d' ' -f1) / $(( $( grep processor /proc/cpuinfo | wc -l ) + 4 )) ))
split -l $SPLITCOUNT $TEMP $TEMP
# nested loops, for each target and for each chunk, start a background copy
for DEST in 'cat $DSTLIST' ; do
# this selects the "user@host" from user@host:/target/path
HOST=$(expr substr $DEST 1 $(($(expr index $DEST :)-1)))
# this selects the "/target/path" from user@host:/target/path
DIR=$(expr substr $DEST $(($(expr index $DEST :)+1)) $(expr length $DEST))
# loop over all the split tempfiles with ${TEMP}??
for I in ${TEMP}?? ; do
# use cpio in copy-out mode to stream the files through ssh
# then ensure the target is in place in the remote host, cd into it,
# and copy-in the files.
# note the '&' at the end backgrounds this command, so the loop
# will continue and generate more concurrent background jobs
cat $I | cpio -o | ssh $HOST \
"mkdir $DIR ; cd $DIR && cpio -idum --no-absolute-filenames" &
# sleep for a second before the next spawn to allow for ssh auth
# and so sshd doesn't start dropping new sessions
sleep 1
done
done
# cleanup the tempfiles
rm ${TEMP}??
rm $TEMP
Veja também link para referência adicional sobre o cpio e a inspiração para esse script.
Edit: Sintaxe alternativa para apenas um src dst, sem criar o arquivo destr do srcfile:
multi-cpio.sh <(echo "/path/to/src") <(echo "user@host:/path/to/dest")