我有一个小脚本,它循环遍历文件夹的所有文件并执行(通常是持久的)命令。基本上是
for file in ./folder/*;
do
./bin/myProgram $file > ./done/$file
done
(请忽略语法错误,这只是伪代码)。
我现在想同时运行这个脚本两次。显然,如果./done/$file存在,则不需要执行。所以我将脚本更改为
for file in ./folder/*;
do
[ -f ./done/$file ] || ./bin/myProgram $file >./done/$file
done
所以基本上问题是:两个脚本(或者通常不止一个脚本)实际上是否有可能位于同一点并检查done
失败的文件是否存在并且命令运行两次?
这将是完美的,但我非常怀疑。这太容易了:D 如果它们可能处理同一个文件,是否可以以某种方式“同步”脚本?
答案1
这是可能的,并且在现实中确实发生了。用一个锁定文件以避免这种情况。一个例子,来自上述页面:
if mkdir /var/lock/mylock; then
echo "Locking succeeded" >&2
else
echo "Lock failed - exit" >&2
exit 1
fi
# ... program code ...
rmdir /var/lock/mylock
答案2
脚本的两个实例当然可以以这种方式交互,导致命令运行两次。这被称为竞争条件。
避免这种竞争情况的一种方法是每个实例通过将其移动到另一个目录来获取其输入文件。移动文件(在同一文件系统内)是原子。移动输入文件可能并不理想,而且这已经变得有点复杂了。
mkdir staging-$$ making-$$
for input in folder/*; do
name=${x#folder/}
staging=staging-$$/$name
output=making-$$/$name
destination=done/$name
if mv -- "$input" "$staging" 2>/dev/null; then
bin/myProgram "$staging" >"$output"
mv -- "$output" "$destination"
mv -- "$staging" "$input"
fi
done
使用广泛可用的工具并行处理文件的一种简单方法是GNU 使, 使用-j
并行执行标志。这是此任务的 makefile(记住使用制表符缩进命令):
all: $(patsubst folder/%,done/%,$(wildcard folder/*))
done/%: folder/%
./bin/myProgram $< >[email protected]
mv [email protected] $@
运行make -j 3
以并行运行 3 个实例。
也可以看看并行执行四个任务...我该怎么做?
答案3
我有一种感觉,您确实在尝试并行运行多个作业,而锁定文件只是达到目的的一种手段。
如果您有 GNU Parallelhttp://www.gnu.org/software/parallel/安装后你可以这样做:
parallel ./bin/myProgram ::: ./folder/*
它将在每个核心上并行运行 myProgram。
您可以简单地通过以下方式安装 GNU Parallel:
wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
观看 GNU Parallel 的介绍视频以了解更多信息: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
答案4
锁定的问题在于您需要一种创建不可中断的锁(有时称为atomar)的方法。正如克里斯在他的回答中所写的mkdir
那样,这是一个不间断的操作(创建文件不是这样的操作)。
还有一个高级命令 - 通常隐藏在procmail
包中:lockfile
。该命令具有一些不错的功能,并且可以轻松地在您自己的脚本中使用,而无需“重新发明轮子”(例如编写您自己的基于目录创建锁定的函数)。