使用parallel选项时,如何将多个子命令传递给xargs

时间:2014-07-06 17:45:08

标签: bash find xargs

我正在尝试编写一个bash脚本来处理多个流中的大型目录树和rsync。从本网站的其他研究中我构建了以下内容。假设命令运行:

program.sh / input / location / output / location $ threads

我的脚本中的关键行是

cd $1; find . -depth \( -type d -printf \""%p/\"\n" \) | xargs -n1 -P$3 -I% rsync -lptgoDds --delete --backup --backup-dir=$INCREMENTALS/$DATE/$1 % $2/%

上述想法是在某个点找到所有目录,然后将它们传递给rsync命令的并行实例,将数据从$ 1复制到$ 2.

我遇到的问题是rsync可能必须根据输入的解析方式创建尚不存在的嵌套文件夹。 (至少我认为这是我所看到的错误的原因)。为了解决这个问题,我想我可以在rsync中发出两个命令。第一个命令将生成目录,第二个命令将启动rsync。

这样的事情:

cd $1; find . -depth \( -type d -printf \""%p/\"\n" \) | xargs -n1 -P$3 -I% 'mkdir -p %;rsync -lptgoDdsv --delete % $2/%;'

但这似乎也不起作用。

所以现在玩了一段时间,我正在寻求帮助。 : - )

3 个答案:

答案 0 :(得分:1)

您无法将单引号中的复杂命令传递给xargs。但您可以将其传递给sh,然后将其传递给xargs

cd $1; find . -depth \( -type d -printf \""%p/\"\n" \) | xargs -n1 -P$3 -I% sh -c 'mkdir -p %;rsync -lptgoDdsv --delete % $2/%;'

(我无法对此进行测试。可能还需要进行一些调整。)

答案 1 :(得分:0)

似乎GNU Parallel http://www.gnu.org/software/parallel/man.html#example__parallelizing_rsync的例子与你想要的非常接近:

cd src-dir; find . -type f -size +100000 | parallel -v ssh fooserver mkdir -p /dest-dir/{//}\;rsync -Havessh {} fooserver:/dest-dir/{}

相反,这应该有效:

cd $1; find . -depth -type d | parallel -P$3 mkdir -p $INCREMENTALS/$DATE/$1 $2/{}\; rsync -lptgoDds --delete --backup --backup-dir=$INCREMENTALS/$DATE/$1 {} $2/{}

如果没有为您的系统打包GNU Parallel,则应在10秒内安装:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

要了解更多信息:观看介绍视频,以便快速了解: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

完成教程(man parallel_tutorial)。你命令行 会爱你的。

答案 2 :(得分:0)

回过头来重新发布我认为的答案。我不得不使用shell调用来做我需要做的事情,在经过大量的试验和错误之后,我发现答案非常简单,将字段传递给子shell。通过导出它们,它们可用于子壳,它就像一个魅力。这是我目前的剧本。

#!/bin/bash
set -x

export INCREMENTALS="/var/backup/data"
export DATE=`date +%F`
export SRCDIR=$1
export TARGETDIR=$2
export THREADS=$3


cd $SRCDIR; find . -type d -print0 | xargs -0 -n1 -P$THREADS -I {} sh -c 'echo $TARGETDIR/"{}"; mkdir -p $TARGETDIR/"{}"; rsync -lptgoDdXvz --delete --backup --backup-dir=$INCREMENTALS/$DATE/.$SRCDIR "{}"/ $TARGETDIR/"{}"'

要运行脚本,请使用以下序列:

rsync.sh /from/dir /to/dir 20

前两个参数很明显,“20”是您要调用的rsync的线程数。

所以这样你就可以将许多并行的rsync推到耗尽机器的程度。我发现的唯一问题是,如果有成千上万个文件的目录,并行性就会崩溃,因为所有其他文件都完成了,而你却被困在最长的文件后面。我正试图找到一种方法来为第二轮做更多的喷雾方法。

我现在唯一的另一个问题是我的记忆消耗随着时间的推移而上升。我有一种有趣的感觉,这是一个与我的脚本无关的泄漏,但我担心我可能会有一些无限的元素导致不断增加的内存使用。仍然是另一个需要解决的问题,与此无关。

net-net答案是“导出”函数,然后子shell正确地查看内容并且它的效果非常好。