Awk inplace opção com print statement

4

Na versão recente do awk há uma opção inplace que pode ser usada para operações no local semelhantes à opção sed 's -i. No entanto, não posso fazê-lo funcionar com a instrução print . Vamos ver meu exemplo. O conteúdo do teste de arquivo é:

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

Se eu não usar -i inplace , posso obter o resultado desejado no console.

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

Quando adiciono -i inplace , é isso que recebi.

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:~#

Como melhorar meu código e conseguir o que eu quero?

Atualizar

Minha versão do 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:~#

Update2

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:~#
    
por Ogrish Man 11.05.2015 / 18:57

2 respostas

2

Acho que você precisa usar BEGINFILE em vez de BEGIN e ENDFILE em vez de END para o início e o fim para imprimir no arquivo.

Pelo menos isso funciona no 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
    
por 11.05.2015 / 19:21
0

Os loops BEGIN e END são executados antes de o arquivo ser processado e depois de processado integralmente. O -i inplace só faz sentido enquanto um arquivo está sendo processado. Não posso ter certeza sem verificar o código-fonte, mas, portanto, parece razoável que o BEGIN e END não funcionem aqui.

Como já foi sugerido, é para isso que BEGINFILE e ENDFILE são. Se isso não funcionar em sua configuração, você terá que usar soluções alternativas. Embora a correspondência da primeira linha seja fácil ( if(NR==1){print "begin"} ), a correspondência da última linha é um pouco mais complicada. Alguns truques que você pode usar são:

  1. Adicione as linhas inicial e final usando outra ferramenta:

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

    ou

    printf "begin\n%s\nend" "$(cat file)" 
    
  2. Use awk para o "começo" e adicione o "fim" mais tarde:

    awk -i inplace  'NR==1{print "begin"}$1=="11"{print "111" $2; next}1;' file && 
        echo "end" >> file
    
  3. Faça tudo usando uma ferramenta que entenda eof . O -a de Perl faz com que ele aja como awk : ele irá dividir os campos no espaço em branco no array @F . Assim como awk , a opção -F permite definir o delimitador de campo. A opção -i edita o arquivo:

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

Tags