【问题标题】:How to flush output when using inplace editing with awk?使用 awk 就地编辑时如何刷新输出?
【发布时间】:2019-09-12 16:30:33
【问题描述】:

我想使用 awk 编辑大文件 inplace 的一列。如果由于任何原因进程中断/停止,我不想丢失已经完成的工作。我尝试添加fflush,但似乎与inplace 不符。

为了模拟想要的结果,这里有一个包含 3 列的测试文件。最后一列全为零。

paste -d '\t' <(seq 1 10) <(seq 11 20) | 
    awk 'BEGIN {FS="\t"; OFS=FS} {$(NF+1)=0; print}' > testfile

然后我想替换最后一列中的值。在这个简单的示例中,我只是将它们替换为第一列和第二列的总和。我正在添加系统睡眠,因此可能会在中间中止脚本以查看结果。

awk -i inplace 'BEGIN {FS="\t"; OFS=FS} $3==0{$3=$1+$2; print; fflush(); system("sleep 1")}' testfile

如果你运行脚本并在它结束之前中止它(ctrl+z),测试文件不会改变。

是否有可能达到预期的结果(当脚本中断或停止时得到部分结果)?我该怎么做?

【问题讨论】:

  • 尝试不使用-i inplace 并通过重定向到新文件(即awk 'code' file &gt; newFile)来保存输出。 (您始终可以重命名您的 orig 文件,但这样您就失去了流程的可追溯性)。

标签: awk in-place fflush


【解决方案1】:

“就地”编辑并不是真的。一个临时文件保存输出,并替换脚本末尾的输入。

实际就地编辑会很慢:除非输出与输入的长度相同,否则文件大小需要更改,awk 将不得不重写整个文件(至少当前行之后的所有内容)在每次缓冲区刷新时。请注意来自the documentation 的警告:

如果程序过早终止……可能会留下一个临时文件。

您可以编写一些恢复代码,以便在中止后将该临时文件与您的输入合并。

或者,您可以将脚本调整为每次运行只修改一行(并简单地打印后续的每一行,未修改),然后重新运行它,直到没有任何更改可做。这将强制awk 在每次更改时重新写入文件。它会很慢,但是没有任何快速的方法可以从文件中间删除数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    相关资源
    最近更新 更多