带 print 语句的 awk 就地选项

带 print 语句的 awk 就地选项

在 awk 的最新版本中,有一个inplace选项可用于执行类似于sed-i 选项的就地操作。但是我无法让它与print声明一起工作。让我们看看我的例子。文件test的内容为:

11 aa
22 bb
root@localhost:~# cat test
11 aa
22 bb

如果我不使用-i inplace,我可以在控制台中得到我想要的结果。

root@localhost:~# awk 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' test
begin
111aa
22 bb
end

当我添加时-i inplace,这就是我得到的。

root@localhost:~# awk -i inplace 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' test
begin
end
root@localhost:~# cat test
111aa
22 bb
root@localhost:~#

如何改进我的代码并得到我想要的东西?

更新


我的 awk 版本是4.1.1.

root@localhost:~# awk --version
GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2-p3, GNU MP 6.0.0)
Copyright (C) 1989, 1991-2014 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
root@localhost:~#

更新2


root@localhost:~# awk --version
GNU Awk 4.1.2, API: 1.1
Copyright (C) 1989, 1991-2015 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
root@localhost:~# cat file
11 aa
22 bb
root@localhost:~# awk 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' file
begin
111aa
22 bb
end
root@localhost:~# awk -i inplace 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' file
begin
end
root@localhost:~# cat file
111aa
22 bb
root@localhost:~#

答案1

我认为您需要使用 BEGINFILE 而不是 BEGIN,使用 ENDFILE 而不是 END 作为开始和结束打印到文件中。

至少这在 cygwin 上有效。

Rob@Rob-PC /cygdrive/c/tmp
$ awk --version
GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2, GNU MP 6.0.0)
Copyright (C) 1989, 1991-2014 Free Software Foundation.


Rob@Rob-PC /cygdrive/c/tmp
$ echo "11 aa
22 bb" > test

Rob@Rob-PC /cygdrive/c/tmp
$ awk -i inplace 'BEGINFILE{print "begin"} $1=="11"{print "111" $2; next} 1; ENDFILE{print "end" >> "test"}' test

Rob@Rob-PC /cygdrive/c/tmp
$ cat test
begin
111aa
22 bb
end

答案2

BEGIN和循环END在处理文件之前和完全处理文件之后运行。只有-i inplace在处理文件时才有意义。如果不检查源代码,我无法确定,但因此,BEGINandEND在这里不起作用似乎是合理的。

正如已经建议的,这就是BEGINFILEENDFILE的用途。如果这些在您的设置中不起作用,您将不得不使用解决方法。虽然匹配第一行很容易 ( if(NR==1){print "begin"}),但匹配最后一行则有点棘手。您可以使用的一些技巧是:

  1. 使用另一个工具添加开始线和结束线:

    perl -i -007ne 'print "begin\n${_}end\n"' file &&
        awk -i inplace '$1=="11"{print "111" $2; next}1;' file
    

    或者

    printf "begin\n%s\nend" "$(cat file)" 
    
  2. 用于awk“开始”并稍后添加“结束”:

    awk -i inplace  'NR==1{print "begin"}$1=="11"{print "111" $2; next}1;' file && 
        echo "end" >> file
    
  3. 使用可以理解的工具来完成整个事情eof。 Perl 的-aswitch 使它的行为类似于awk:它将空格上的字段分割到@F数组中。就像 一样awk,该-F开关允许您设置字段分隔符。开关-i就地编辑文件:

    perl -i -lane '$.==1 && print "begin"; eof && print "end"; 
                   if($F[0]=="11"){print "111$F[0] $F[1]"; next} print;' file
    

相关内容