原子地删除文件的第一行并返回它
atomically removing the first line of a file AND returning it
我想使用纯文本文件作为我的应用程序的任务队列(用于写入数据库,尽管这无关紧要),其中:
- 我通过
echo "some task" >> task_queue.txt
将项目添加到队列
- 我从队列中自动删除了一个项目
对于 2。如果我在多个线程或进程中 accessing/modifying task_queue.txt
,我不知道如何避免竞争条件。以下不是原子的:
ITEM=`head -1 task_queue.txt`
sed -i '1d' task_queue.txt
# process the item in the application
Bash 是否提供了比使用锁定文件更优雅的方式来执行此操作?我以前从未使用过 flock
,所以我不知道这是否很混乱(例如,当我的应用程序的任务处理失败时)。
在检查文件是否被访问和对文件进行操作之间,所有这些都存在竞争条件。虽然大概检查和操作之间的时间会很短。
一种方法是使用 pgrep
和 -f
选项来匹配完整的命令行,并匹配文件是否匹配,即是否有任何进程访问该文件。这假设进程没有修改它的命令行。
这可以做到:
if ! 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
的 STDOUT 和 STDERR 发送到 /dev/null
,这可能并不总是可取的,因为可能有一些 warning/error,因为我们只依赖于退出状态,所以所有这些都将被误认为文件正在使用中。如果 lsof
/fuser
对不同的事件有不同的退出状态,这将更容易实现,但我能看到的是 1
对于每种失败或不匹配。
虽然我无法确认它是原子的,但这比我自己写的任何东西(可能)都更原子,并且对于我的非关键任务应用程序来说已经足够好了:
sed -i -e '1 w /dev/stdout' -e '1d' task_queue.txt
我想使用纯文本文件作为我的应用程序的任务队列(用于写入数据库,尽管这无关紧要),其中:
- 我通过
echo "some task" >> task_queue.txt
将项目添加到队列
- 我从队列中自动删除了一个项目
对于 2。如果我在多个线程或进程中 accessing/modifying task_queue.txt
,我不知道如何避免竞争条件。以下不是原子的:
ITEM=`head -1 task_queue.txt`
sed -i '1d' task_queue.txt
# process the item in the application
Bash 是否提供了比使用锁定文件更优雅的方式来执行此操作?我以前从未使用过 flock
,所以我不知道这是否很混乱(例如,当我的应用程序的任务处理失败时)。
在检查文件是否被访问和对文件进行操作之间,所有这些都存在竞争条件。虽然大概检查和操作之间的时间会很短。
一种方法是使用 pgrep
和 -f
选项来匹配完整的命令行,并匹配文件是否匹配,即是否有任何进程访问该文件。这假设进程没有修改它的命令行。
这可以做到:
if ! 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
的 STDOUT 和 STDERR 发送到 /dev/null
,这可能并不总是可取的,因为可能有一些 warning/error,因为我们只依赖于退出状态,所以所有这些都将被误认为文件正在使用中。如果 lsof
/fuser
对不同的事件有不同的退出状态,这将更容易实现,但我能看到的是 1
对于每种失败或不匹配。
虽然我无法确认它是原子的,但这比我自己写的任何东西(可能)都更原子,并且对于我的非关键任务应用程序来说已经足够好了:
sed -i -e '1 w /dev/stdout' -e '1d' task_queue.txt