防止文件被linux中的另一个进程移动

时间:2013-10-21 14:21:05

标签: linux bash shell

我的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。

3 个答案:

答案 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个,你就必须进行一些同步。基本上有两种选择:

  1. 将锁定放在列表+副本周围。使用flock(1)和锁定文件最容易完成。有两种方法可以调用它:

    1. 通过flock调用整个复制操作:

      flock targdir -c copy-script
      

      这要求您将应该排除的部分作为单独的脚本。

    2. 通过文件描述符锁定。在复制之前,请执行

      exec 3>targdir/.lock
      flock 3
      

      之后

      flock -u 3
      

      这使您只能锁定部分脚本。这在Cygwin中不起作用(但你可能不需要)。

  2. 逐个移动文件,直到您有足够的文件。

    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个文件,但可能是随机选择。

  3. 另外,如果您不是绝对需要在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扩展。