使用awk将修改保存到位


135

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

我确实知道我可以使用重定向来编写更改。但是,有选择awk吗?


另请参阅serverfault.com/a/547331/313521,以获取有关“使用重定向在适当位置编辑文件”的更一般答案。
2015年

@Wildcard。那里的解决方案非常脆弱。绝对不能保证事件的顺序,使用该解决方案可能会截断数据。顺便说一句,我不能直接在该站点上发表评论,因为我需要在该站点上发表50次报告。我永远也不会明白为什么SO会分成Unix / Linux和服务器admin等。海事组织,那是一个错误。
威廉·珀塞尔

@WilliamPursell,“不保证事件的顺序” —实际上是错误的。解决方案唯一的脆弱性是内容的长度大于命令的最大长度。但是,可以保证事件的顺序。
通配符

@Wildcard什么标准可以保证订购?
威廉·珀塞尔

@WilliamPursell由bash文档保证。对于其他外壳,我不知道。(顺便说一句,如果您链​​接您的帐户,您将获得100个代表协会奖金并可以发表评论。)
通配符

Answers:


142

在最新的GNU Awk(从4.1.0版本开始)中,它具有“就地”文件编辑的选项:

使用新工具构建的“ 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

1
@sudo_O-感谢您的“就地”演示。支持您的答案!
lind

看起来该选项可能已被删除?对于4.1.3,我有“ -i includefile --include = includefile”
Keith

1
@基思我有同样的问题。我刚试过,它可以在我的4.1.3上运行。 inplace实际上,gawk根据iiSeymour的答案,它实际上是一个包含在库中的库,因此inplace也可以作为includefile
cxw

这里有个重要的警告:“可见”数组将填充命令中包含的所有文件中的重复行。因此,如果每个文件都有一个公共标头,则将在第一个文件之后的每个文件中将其删除。如果您想独立对待每个文件,则需要在* .txt中为f做类似的事情;做gawk -i inplace'!seen [$ 0] ++'“ $ f”; 完成
尼克K9,19年

136

除非您拥有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

我很高兴已经添加了此功能,但对我来说,实现不是很糟糕,因为强大的功能来自语言的简洁性,而且imo-i inplace长度为8个字符。

这是官方单词手册的链接。


您的“第一个”示例不应该更像:awk '{ gsub(/foo/, "bar" ) } ; { print $0 }' file > tmp.txt && mv -v tmp.txt file吗?
托尼·巴尔甘斯基

令我惊讶的是,截至2019年4月,其价格仍为4.02。不要让任何人告诉你这样的版本,这样的版本将可用。
约翰·伦泽

Litte短于from awk '{print $0}' file | sponge file使用。spongemoreutils
brablc

15

@sudo_O有正确的答案

这行不通:

someprocess < file > file

Shell 将控制权移交给某个进程之前执行重定向(redirects)。该>重定向将文件截断至零大小(重定向输出)。因此,当某个进程启动并想要从文件中读取时,没有可供读取的数据。


14

只是一个小技巧

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

奇迹般有效!但是有可能将awk命令保存到变量中,然后在漂亮的技巧中使用它吗?
ashrasmun

13

一种替代方法是使用sponge

awk '{print $0}' your_file | sponge your_file

在其中用'{print $0}'awk脚本和your_file要在适当位置编辑的文件名替换。

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


海绵的标准/便携式程度如何?
汤玛斯(Thomas)

2
sponge是的一部分moreutils。因此,默认情况下,它不会在大多数系统中显示。但是看起来至少sponge它本身具有足够的可移植性,并且几乎可以在任何地方运行。
MarSoft

1
与-based相比,此解决方案的缺点teesponge在写入之前会将所有内容读取到RAM,因此它将冻结在大文件上。
MarSoft

5

以下将无法正常工作

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

这应该工作

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

3

如果您想要一个仅awk的解决方案而不创建临时文件并且可用于version!=(gawk 4.1.0):

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

4
但这是否会将整个文件缓冲到内存中?考虑一个20GB的文件。
阿米特·奈杜

0

使用三通

 awk '{awk code}' file | tee file

tee命令走位和后执行awk命令完成因|


5
这是不正确的。这两个命令并行执行,并且数据立即通过管道流化。任何大于缓冲区(我的计算机上为8192字节)的文件都将被截断,并且您将丢失数据。
tripflag
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.