首先也是最重要的:rename 是 atomic。一个文件不可能被移动两次。其中一个移动将失败,因为该文件不再存在。如果脚本并行运行,则两个文件都列出相同的 10 个文件,而不是前 10 个文件移动到/tmp/task1
和接下来的 10个文件,/tmp/task2
您可能会得到 4 个移动到/tmp/task1
和 6 个到/tmp/task2
. 或者可能是 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 扩展。