原子地删除文件的第一行并返回它

时间:2016-10-16 03:18:56

标签: bash file locking atomic

我想使用纯文本文件作为我的应用程序的任务队列(用于写入数据库,尽管这是无关紧要的),其中:

  1. 我通过echo "some task" >> task_queue.txt
  2. 将一个项目添加到队列中
  3. 我原子地从队列中删除一个项目
  4. 对于2.如果我在多个线程或进程中访问/修改task_queue.txt,我不知道如何避免竞争条件。以下不是原子的:

    ITEM=`head -1 task_queue.txt`
    sed -i '1d' task_queue.txt
    # process the item in the application
    

    Bash是否提供了比使用锁定文件更优雅的方法?我之前从未使用过flock因此我不知道这是否很混乱(例如,当我的应用程序的任务处理失败时)。

2 个答案:

答案 0 :(得分:1)

所有这些都受到竞争条件的影响,在检查文件是否被访问以及对文件进行操作之间。虽然大概是检查和操作之间的时间非常短。

一种方法是使用-fif ! pgrep -f task_queue.txt &>/dev/null; then ## File not Open, do stuff else ## File is Open, do stuff fi 选项匹配完整命令行,如果文件匹配则匹配,即访问该文件的任何进程。这假设该过程没有修改它的命令行。

这可以做到:

lsof

另一种方法包括解析fuser/proc/PID/fd/*(这与解析if ! lsof /path/to/task_queue.txt &>/dev/null; then ## File not Open, do stuff else ## File is Open, do stuff fi 相同):

fuser

同样if ! fuser /path/to/task_queue.txt &>/dev/null; then ## File not Open, do stuff else ## File is Open, do stuff fi

lsof

请注意,这里我们将fuser / /dev/null的STDOUT和STDERR发送到lsof,这可能并不总是可取的,因为可能存在一些警告/错误,并且因为我们仅依赖于退出状态,所有这些都将被错误处理,因为文件正在使用中。如果fuser / 1针对不同的事件具有不同的退出状态,则会更容易实现,但我可以看到styles.xml针对每种类型的失败或不匹配。

答案 1 :(得分:0)

虽然我不能确认它是原子的,但它比我自己写的任何东西(可能)都要原子化得多,并且对于我的非任务关键型应用来说已经足够了:

sed -i -e '1 w /dev/stdout' -e '1d' task_queue.txt

(学分:https://unix.stackexchange.com/a/108479/7000