GNU 并行:从作业日志中删除行会中断并行更新它
GNU parallel: deleting line from joblog breaks parallel updating it
如果你 运行 GNU parallel with --joblog path/to/logfile
然后从所述日志文件中删除一行 while parallel is 运行ning, GNU parallel不再能够将未来完成的作业附加到它。
执行此 MWE:
#!/usr/bin/bash
parallel -j1 -n0 --joblog log sleep 1 ::: $(seq 10) &
sleep 5 && sed -i '$ d' log
如果您 tail -f log
在执行之前,您可以看到并行一直写入此文件。但是,如果您在 10 秒后 cat log
,您会发现在第三个条目左右之后,磁盘上的实际文件中没有任何内容被写入。
这背后的原因是什么?有没有办法从文件中删除一些东西并且让 GNU parallel 仍然能够写入它?
关于为什么会发生这种情况的一些背景:
使用 GNU parallel,我在 --sshloginfile
的远程机器上开始了一些工作。然后我需要 pkill
在其中一台机器上做一些工作,因为一位同事需要使用它(我随后从 sshloginfile 中删除了机器,这样并行就不会为新的 运行 重用它).如果你 pkill
这些进程在远程机器上启动,它们的 Exitval 为 0(看起来它们完成时没有问题;你不能说它们已被杀死)。我想立即从作业日志中删除它们,以便稍后 parallel --resume
重新启动时,并行可以查看作业日志并确定缺少的内容。
事实证明,这是个坏主意,因为现在我的工作日志没用了。
虽然@MarkSetchell 在他的评论中是绝对正确的,但这里的根本问题是由于 man sed
撒谎:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if SUFFIX supplied)
sed -i
没有就地编辑文件。
它的作用是在同一个目录下制作一个临时文件,在编辑的同时将输入文件复制到临时文件中,最后将临时文件重命名为输入文件的名称。类似这样:
sed '$ d' log > sedXxO11P
mv sedXxO11P log
很明显,原始日志和 sedXxO11P 具有不同的 inode - 让我们称它们为 ino1 和 ino2。 GNU Parallel 打开了 ino1 并且真的不知道 ino2 的存在。 GNU Parallel 会愉快地追加到 ino1 上,完全不知道当它关闭文件时,文件会消失,因为它已经被取消链接了。
所以需要在不改变inode的情况下改变文件内容:
#!/usr/bin/bash
seq 10 | parallel -j1 -n0 --joblog log sleep 1 &
sleep 5
# Obvious race condition here:
# Anything appended to log before sed is done is lost.
# This can be avoided by suspending parallel while running this
tmp=$RANDOM$$
cp log $tmp
(rm $tmp; sed '$ d' >log) < $tmp
wait
cat log
这现在有效。但不要指望这是一项受支持的功能 - 永远。
如果你 运行 GNU parallel with --joblog path/to/logfile
然后从所述日志文件中删除一行 while parallel is 运行ning, GNU parallel不再能够将未来完成的作业附加到它。
执行此 MWE:
#!/usr/bin/bash
parallel -j1 -n0 --joblog log sleep 1 ::: $(seq 10) &
sleep 5 && sed -i '$ d' log
如果您 tail -f log
在执行之前,您可以看到并行一直写入此文件。但是,如果您在 10 秒后 cat log
,您会发现在第三个条目左右之后,磁盘上的实际文件中没有任何内容被写入。
这背后的原因是什么?有没有办法从文件中删除一些东西并且让 GNU parallel 仍然能够写入它?
关于为什么会发生这种情况的一些背景:
使用 GNU parallel,我在 --sshloginfile
的远程机器上开始了一些工作。然后我需要 pkill
在其中一台机器上做一些工作,因为一位同事需要使用它(我随后从 sshloginfile 中删除了机器,这样并行就不会为新的 运行 重用它).如果你 pkill
这些进程在远程机器上启动,它们的 Exitval 为 0(看起来它们完成时没有问题;你不能说它们已被杀死)。我想立即从作业日志中删除它们,以便稍后 parallel --resume
重新启动时,并行可以查看作业日志并确定缺少的内容。
事实证明,这是个坏主意,因为现在我的工作日志没用了。
虽然@MarkSetchell 在他的评论中是绝对正确的,但这里的根本问题是由于 man sed
撒谎:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if SUFFIX supplied)
sed -i
没有就地编辑文件。
它的作用是在同一个目录下制作一个临时文件,在编辑的同时将输入文件复制到临时文件中,最后将临时文件重命名为输入文件的名称。类似这样:
sed '$ d' log > sedXxO11P
mv sedXxO11P log
很明显,原始日志和 sedXxO11P 具有不同的 inode - 让我们称它们为 ino1 和 ino2。 GNU Parallel 打开了 ino1 并且真的不知道 ino2 的存在。 GNU Parallel 会愉快地追加到 ino1 上,完全不知道当它关闭文件时,文件会消失,因为它已经被取消链接了。
所以需要在不改变inode的情况下改变文件内容:
#!/usr/bin/bash
seq 10 | parallel -j1 -n0 --joblog log sleep 1 &
sleep 5
# Obvious race condition here:
# Anything appended to log before sed is done is lost.
# This can be avoided by suspending parallel while running this
tmp=$RANDOM$$
cp log $tmp
(rm $tmp; sed '$ d' >log) < $tmp
wait
cat log
这现在有效。但不要指望这是一项受支持的功能 - 永远。