使用 awk 保存修改

Posted

技术标签:

【中文标题】使用 awk 保存修改【英文标题】:Save modifications in place with awk 【发布时间】:2013-05-07 22:32:39 【问题描述】:

我正在学习awk,我想知道是否有将更改写入文件的选项,类似于sed,我将使用-i 选项将修改保存到文件。

我明白我可以使用重定向来编写更改。但是awk 中是否有一个选项可以做到这一点?

【问题讨论】:

如果有人想用非 GNU awk 进行就地保存,也可以使用以下链接 ***.com/questions/59243104/… 供参考。 【参考方案1】:

在 GNU Awk 4.1.0(2013 年发布)及更高版本中,它有 "inplace" file editing 的选项:

[...] 使用新工具构建的“inplace”扩展可用于模拟 GNU“sed -i”功能。 [...]

示例用法:

$ gawk -i inplace ' gsub(/foo/, "bar") ;  print ' file1 file2 file3

保留备份:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak ' gsub(/foo/, "bar") 
>  print ' file1 file2 file3

【讨论】:

看起来该选项可能已被删除?在 4.1.3 中,我有“-i includefile --include=includefile” @Keith 我也有同样的问题。我刚刚尝试过,它适用于我的 4.1.3。根据iiSeymour's answer,inplace 实际上是一个包含在gawk 中的库,所以inplace 是可以作为includefile 包含的东西。 这里有一个重要的警告:'seen' 数组将填满命令中包含的所有文件的重复行。因此,如果每个文件都有例如一个共同的标题,将在第一个文件之后的每个文件中删除。如果您想独立处理每个文件,则需要在 *.txt 中执行类似 for f 的操作;做 gawk -i inplace '!seen[$0]++' "$f";完成【参考方案2】:

除非您有 GNU awk 4.1.0 或更高版本...

您不会有像 sed 的 -i 这样的选项,所以改为:

$ awk 'print $0' file > tmp && mv tmp file

注意:-i 不是魔术,它还创建了一个临时文件sed 只是为您处理它。


从 GNU awk 4.1.0...

GNU awk 在 4.1.0 版中添加了此功能(2013 年 10 月 5 日发布)。它不像发布的说明中描述的那样直接提供-i 选项:

新的 -i 选项(来自 xgawk)用于加载 awk 库文件。这与 -f 的不同之处在于第一个非选项参数 被视为脚本。

您需要使用捆绑的 inplace.awk 包含文件来正确调用扩展,如下所示:

$ cat file
123 abc
456 def
789 hij

$ gawk -i inplace 'print $1' file

$ cat file
123
456
789

变量INPLACE_SUFFIX可用于指定备份文件的扩展名:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak 'print $1' file

$ cat file
123
456
789

$ cat file.bak
123 abc
456 def
789 hij

我很高兴添加了这个功能,但对我来说,实现并不是很尴尬,因为它的强大之处在于语言的简洁性,而且-i inplace 的 8 个字符太长了i.m.o

这里是manual 的官方链接。

【讨论】:

您的“第一个”示例不应该更像:awk ' gsub(/foo/, "bar" ) ; print $0 ' file > tmp.txt && mv -v tmp.txt file 吗? 令我惊讶的是,截至 2019 年 4 月,仍然是 gawk 4.0.2。不要让任何人告诉你这样那样的版本将可用。 短一点的awk 'print $0' file | sponge file 使用来自moreutilssponge 请注意,mv tmp file 通常是不够的 - 文件权限可能已更改,必须修复。 -i inplace 没有这个问题。【参考方案3】:

只是一个有效的小技巧

echo "$(awk 'awk code' file)" > file

【讨论】:

像魅力一样工作!但是是否有可能将 awk 命令保存到变量中并在您的巧妙技巧中使用它? -i inplace 方法破坏了硬链接,这个 hack 遵循硬链接♥♥ 这太棒了!【参考方案4】:

@sudo_O 拥有权限answer。

这不行:

someprocess < file > file

shell 在将控制权移交给某个进程 (redirections) 之前 执行重定向。 &gt; 重定向会将文件截断为零大小 (redirecting output)。因此,当某个进程启动并想要从文件中读取数据时,已经没有数据可供它读取了。

【讨论】:

【参考方案5】:

另一种方法是使用sponge:

awk 'print $0' your_file | sponge your_file

您将'print $0' 替换为您的awk 脚本,将your_file 替换为您要就地编辑的文件的名称。

sponge 在将输入保存到文件之前将其完全吸收。

【讨论】:

海绵有多标准/便携? spongemoreutils 的一部分。所以它不会在大多数系统中默认出现。但看起来至少sponge 本身足够便携,几乎可以在任何地方运行。 与基于tee 的解决方案相比,该解决方案的缺点是sponge 将在写入之前将所有内容读取到RAM,因此它会冻结大文件。【参考方案6】:

以下操作无效

echo $(awk 'awk code' file) > file

这应该可以工作

echo "$(awk 'awk code' file)" > file

【讨论】:

【参考方案7】:

如果您想要一个仅 awk 的解决方案,而无需创建临时文件并且可以与 version!=(gawk 4.1.0) 一起使用:

awk 'a[b++]=$0 END for(c=0;c<=b;c++)print a[c]>ARGV[1]' file

【讨论】:

但这会将整个文件缓冲到内存中吗?考虑一个 20GB 的文件。

以上是关于使用 awk 保存修改的主要内容,如果未能解决你的问题,请参考以下文章

使用 awk 修改文本

awk如何才能直接修改原文件

Linux中使用sed命令或awk命令修改常规配置文件

批量修改文件名

awk之shell快速修改文件名

awk/sed 修改log中的时间戳