在AWK中在文件顶部插入一行

huangapple go评论51阅读模式
英文:

AWK insert line at top of a file

问题

我想在这里做一些解释!
我对awk不太了解,我想知道如何在文件顶部插入一行。

到目前为止,这是我尝试过的内容:

file.txt

内容行
另一行

awk命令

awk  'BEGIN {print "第一行" } {print}' file.txt

输出

第一行
内容行
另一行

然而,当使用-i inplace运行时,不会写入文件,只会给我这个输出

第一行

我想知道我做错了什么,如果你们能解释一下,我会非常感激。

英文:

I would like to get some explanation here!
I'm new to awk and I'd like to know how do I insert a line at to of a file.

This is what I've tried so far

file.txt

content line
another line

awk command

awk  'BEGIN {print "first line" } {print}' file.txt

the output

first line
content line
another line

however, when run with -i inplace doesn't write to the file only gives me this output

first line

I would like to know what I am doing wrong and if you guys can explain it I'd really appreciate.

答案1

得分: 2

BEGIN{} 块在处理任何文件之前被处理,这意味着由 BEGIN{} 块生成的任何输出都只能发送到标准输出。

要将这行插入文件中,您需要将 print "first line" 移动到脚本的主体部分,以便它可以与文件一起处理。

基于在读取输入文件的第一行时插入新行的想法:

awk -i inplace 'FNR==1 {print "first line;"}1' file.txt

cat file.txt

first line
content line
another line

注意:

  • 如果您将多个文件提供给 awkFNR==1 将适用于每个文件,否则如果只有一个输入文件,NR==1 也足够。
  • 独立的 1 是非零的,因此被 awk 视为“true”;在这里,它适用于所有输入行,对于“true”,默认行为是将输入行传递到标准输出(与 {print} 效果相同)。
英文:

The BEGIN{} block is processed before any files are processed which means any output generated by the BEGIN{} block has nowhere to go but to stdout.

To get the line inserted into the file you need to move the print "first line" into the main body of the script where it can be processed along with the file.

One idea based on inserting the new row while reading the first line of the input file:

$ awk -i inplace 'FNR==1 {print "first line"}1' file.txt

$ cat file.txt
first line
content line
another line

NOTES:

  • FNR==1 will apply to each file if you happen to feed multiple files to awk, otherwise NR==1 will also suffice if it's just the one input file
  • the stand-alone 1 is non-zero and thus considered by awk as 'true'; here it applies against all input lines and the default behavior for a 'true' is to pass the input line through to stdout (effectively the same as {print})

答案2

得分: 2

-i inplace 选项包括内置的 inplace.awk 包含文件,以模拟 sed -i 的原地编辑,但这种模拟方法有一些注意事项。

因为它通过调整每个输入文件的处理方式(使用 BEGINFILE 模式)来工作,所以在 BEGIN 选择器中打印的任何内容仍然会输出到启动输出流,而不是到“调整后”的输出流。这是因为在那个时候第一个输入文件尚未开始处理。

所以你将看到 first line 输出到标准输出,然后从输入文件打印的两行被原地写回到该文件。你可能没有意识到最后一部分,因为在写回时没有更改文件中的行。

毫无疑问,这对于 inplace.awk 的创建者来说是一个困难的实现决策,因为需要为多个文件的原地编辑提供支持。问题是:在原地编辑中 BEGIN 中的输出应该放在哪里?

你有几个选项。


首先,如果你知道你只会处理一个文件,你可以使用常规的技巧,使用 BEGIN 但不使用 inplace

awk 'BEGIN {print "first line" } {print}' file.txt > /tmp/$$ && mv /tmp/$$ file.txt

其次,使用 inplace 但不使用 BEGIN,你需要首先决定它应该影响哪个输入文件。如果你希望它影响所有输入文件,那就意味着类似于以下方式:

awk -i inplace 'FNR==1 {print "first line";print;next} {print}' file1.txt file2.txt

如果你只想影响第一个输入文件,使用 NR 而不是 FNR(前者永不减少,后者对每个新的输入文件都重置为1)。


最后,对于所有文件都应该受影响的情况,你可以使用与 inplace 本身使用的相同方法。

由于特殊模式(如 BEGIN)按照定义的顺序执行(而 -i 在你的脚本处理之前执行),所以只需使用 BEGINFILE 而不是 BEGIN,如下所示:

=====
pax@styx:~$ cat xx.001
Original line from xx.001

=====
pax@styx:~$ cat xx.002
Original line from xx.002

=====
pax@styx:~$ cat xx.awk
BEGINFILE {
    print "inserted line"
}
{
    print
}

=====
pax@styx:~$ awk -i inplace -f xx.awk xx.001 xx.002

=====
pax@styx:~$ cat xx.001
inserted line
Original line from xx.001

=====
pax@styx:~$ cat xx.002
inserted line
Original line from xx.002

inplaceBEGINFILE 首先会执行其魔术以捕获输出(每个输入文件),然后你的 BEGINFILE 将在该捕获区域中打印。

英文:

The -i inplace includes the built-in inplace.awk include file to emulate sed -i in-place editing but there are some caveats that come from the method used for this emulation.

Because it works by fiddling with the processing of each input file (by using the BEGINFILE pattern), anything printed in the BEGIN selector still goes to the start-up output stream rather than to the "fiddled" output stream. That's because the first input file has yet to begin processing at that point.

So what you'll see is first line going to standard output then the two lines from the input file being printed in-place back to that file. You just may not have realised that last bit since you don't change the lines in the file when you write them back.

This was no doubt a difficult implementation decision for the creators of inplace.awk since in-place editing over multiple files needs to be catered for. The question is: where should output go in BEGIN for in-place editing?

You have a couple of options here.


First, if you know you'll only ever process one file, you can use the normal trick, with BEGIN but without inplace:

awk 'BEGIN {print "first line" } {print}' file.txt > /tmp/$$ && mv /tmp/$$ file.txt

Second, using inplace but not BEGIN, you need to first decide which of the input files it should affect. If you want it to affect all input files, that means something like:

awk -i inplace 'FNR==1 {print "first line";print;next} {print}' file1.txt file2.txt

If you want it to affect just the first input file, use NR rather than FNR (the former never decreases, the latter resets to one for each new input file).


Finally, for the case where all files should be affected, you can use the same method that inplace itself uses.

As special patterns like BEGIN are executed in order of definition (and -i comes before processing of your script), simply use BEGINFILE rather than BEGIN, as per the following transcript:

=====
pax@styx:~$ cat xx.001
Original line from xx.001

=====
pax@styx:~$ cat xx.002
Original line from xx.002

=====
pax@styx:~$ cat xx.awk
BEGINFILE {
    print "inserted line"
}
{
    print
}

=====
pax@styx:~$ awk -i inplace -f xx.awk xx.001 xx.002

=====
pax@styx:~$ cat xx.001
inserted line
Original line from xx.001

=====
pax@styx:~$ cat xx.002
inserted line
Original line from xx.002

The BEGINFILE from inplace will first weave its magic to capture output (per input file), then your BEGINFILE will print to that capture area.

答案3

得分: 0

$ awk -i inplace 'NR==1{print "第一行";print;next} {print}' file ; cat file
第一行
原始内容行 1
原始内容行 2
英文:

What I would do:

$ awk -i inplace 'NR==1{print "first line";print;next} {print}' file ; cat file
first line
original content line 1
original content line 2

答案4

得分: 0

非awk版本:

我很兴奋地看到-i inplace选项,但在macOS和BSD上不可用。所以除了@paxdiablo的临时文件解决方案之外,以下是如何使用/bin/ed在行前添加内容的方法。

ed -s file.txt << EOF
1i
first line
.
w
EOF
英文:

Non-awk version:

I was excited to see the -i inplace option, but it's not available in macOS and BSDs. So in addition to @paxdiablo's solution of a tmp file, here's how you can prepend lines with /bin/ed.

ed -s file.txt &lt;&lt; EOF
1i
first line
.
w
EOF

huangapple
  • 本文由 发表于 2023年1月9日 07:42:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052083.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定