如何使用 awk 就地更改文件? (与“sed -i”一样)

如何使用 awk 就地更改文件? (与“sed -i”一样)

我有一个awk脚本new.awk

BEGIN { FS = OFS = "," }

NR == 1 {
    for (i = 1; i <= NF; i++)
        f[$i] = i
}

NR > 1 {
    begSecs = mktime(gensub(/[":-]/, " ", "g", $(f["DateTime"])))
    endSecs = begSecs + $(f["TotalDuration"])
    $(f["CallEndTime"]) = strftime("%Y-%m-%d %H:%M:%S", endSecs)
}

{ print }

我在 shell 中调用这个

awk new.awk sample.csv

...但我可以看到终端中的变化。如何在文件中就地进行更改,就像使用时一样sed -i

答案1

GNU awk(常见于 Linux 系统)从 4.1.0 版开始,可以在命令行中包含一个“源库”(请awk参阅-i--include如何安全地使用 gawk 的 -i 选项或 @include 指令?以及下面 Stéphane 对与此相关的安全问题的评论)。随 GNU 分发的源库之一awkinplace

$ cat file
hello
there
$ awk -i inplace '/hello/ { print "oh,", $0 }' file
$ cat file
oh, hello

正如您所看到的,这使得代码的输出awk替换了输入文件。there由于程序不输出该行,因此不会保留该行。

对于awk文件中的脚本,您可以像这样使用它

awk -i inplace -f script.awk datafile

如果该awk变量INPLACE_SUFFIX设置为字符串,则库将以原始文件作为文件名后缀进行备份。

awk -i inplace -v INPLACE_SUFFIX=.bak -f script.awk datafile

如果您有多个输入文件,则每个文件都可以单独就地编辑。但是您可以通过inplace=0在该文件之前的命令行上使用来关闭文件(或一组文件)的就地编辑:

awk -i inplace -f script.awk file1 file2 inplace=0 file3 inplace=1 file4

在上面的命令中,file3不会就地编辑。


要对单个文件进行更便携的“就地编辑”,请使用

tmpfile=$(mktemp)
cp file "$tmpfile" &&
awk '...some program here...' "$tmpfile" >file
rm "$tmpfile"

这会将输入文件复制到临时位置,然后awk在临时文件上应用代码,同时重定向到原始文件名。

按此顺序执行操作(awk在临时文件上运行,而不是在原始文件上运行)可确保原始文件的文件元数据(权限和所有权)不会被修改。

答案2

尝试这个。

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • 将输出重定向到临时文件。
  • 然后将临时文件的内容移动到原始文件。

相关内容