我的bash脚本有问题。 我有两个cron任务,它从同一个文件夹中获取一些文件以供进一步处理。
ls -1h "targdir/*.json" | head -n ${LIMIT} > ${TMP_LIST_FILE}
while read REMOTE_FILE
do
mv $REMOTE_FILE $SCRDRL
done < "${TMP_LIST_FILE}"
rm -f "${TMP_LIST_FILE}"
然后两个脚本实例同时运行同一个文件,并转移到$ SRCDRL,这与实例不同。 问题是如何防止文件被不同的脚本移动?
UPD: 也许我有点不清楚...... 我有文件夹“targdir”,我存储json文件。我有两个cron任务,从该目录中获取一些文件进行处理。例如在targdir中存在25个文件,第一个cron任务应该获得前10个文件并将它们移动到/ tmp / task1,第二个cron任务应该获得下一个10个文件并将它们移动到/ tmp / task2,e.t.c。 但现在前10个文件移动到/ tmp / task1和/ tmp / task2。
答案 0 :(得分:1)
两个cron作业将同一文件移动到同一路径的事实对你来说无关紧要,除非你被其中一个错误所困扰(一个会成功而另一个会失败)。
您可以使用以下方法忽略错误:
...
mv $REMOTE_FILE $SCRDRL 2>/dev/null
...
答案 1 :(得分:1)
由于您的脚本应该从列表中移动特定数量的文件,因此两个实例最多会移动两倍的文件。除非它们甚至相互干扰,否则移动文件的数量可能会更少。
无论如何,这可能是一个糟糕的情况。如果你有办法阻止两个脚本同时运行,你应该这样做。
但是,如果您无法阻止两个脚本实例同时运行,则至少应该强化脚本以防止错误:
mv&#34; $ REMOTE_FILE&#34; &#34; $ SCRDRL&#34; 2 - ;的/ dev / null的
否则你的脚本会产生错误输出(在cron脚本中没有好主意)。
此外,我希望您的${TMP_LIST_FILE}
在两个实例中都不相同(您可以在其中使用$$
来避免这种情况);否则他们甚至会覆盖这个临时文件,在最坏的情况下会导致包含你不想移动的路径的文件损坏。
答案 2 :(得分:1)
首先:重命名是原子的。文件移动两次可能不。其中一个动作将失败,因为文件不再存在。如果脚本并行运行,则会列出相同的10个文件,而不是前10个文件移至/tmp/task1
而下10个文件移至/tmp/task2
,您可以将4个移至/tmp/task1
,将6移至/tmp/task2
{1}}。或者可能是5和5或9和1或任何其他组合。但是每个文件只会在一个任务中结束。
所以没有错误;每个文件仍然只处理一次。但它效率低下,因为你一次可以处理10个文件,但是你只处理5个。如果你想确保在有足够的文件可用时总是处理10个,你就必须进行一些同步。基本上有两种选择:
将锁定放在列表+副本周围。使用flock
(1)和锁定文件最容易完成。有两种方法可以调用它:
通过flock调用整个复制操作:
flock targdir -c copy-script
这要求您将应该排除的部分作为单独的脚本。
通过文件描述符锁定。在复制之前,请执行
exec 3>targdir/.lock
flock 3
之后
flock -u 3
这使您只能锁定部分脚本。这在Cygwin中不起作用(但你可能不需要)。
逐个移动文件,直到您有足够的文件。
ls -1h targdir/*.json > ${TMP_LIST_FILE}
# ^^^ do NOT limit here
COUNT=0
while read REMOTE_FILE
do
if mv $REMOTE_FILE $SCRDRL 2>/dev/null; then
COUNT=$(($COUNT + 1))
fi
if [ "$COUNT" -ge "$LIMIT" ]; then
break
fi
done < "${TMP_LIST_FILE}"
rm -f "${TMP_LIST_FILE}"
mv
有时会失败,在这种情况下,您不会计算文件并尝试移动下一个文件,假设mv
失败,因为文件同时被另一个脚本移动了。每个脚本最多复制$LIMIT
个文件,但可能是随机选择。
另外,如果您不是绝对需要在while
循环中设置环境变量,则可以不使用临时文件。简单地:
ls -1h targdir/*.json | while read REMOTE_FILE
do
...
done
你不能将变量传播出这样的循环,因为它作为管道的一部分在子shell中运行。
如果你确实需要设置环境变量并且能够专门使用bash(我通常会尝试坚持/bin/sh
),你也可以写
while read REMOTE_FILE
do
...
done <(ls -1h targdir/*.json)
在这种情况下,循环在当前shell中运行,但这种重定向是bash扩展。