gawk inplace e stdout


10

É possível usar gawka -i inplaceopção e também imprimir coisas stdout?

Por exemplo, se eu quiser atualizar um arquivo e se houver alguma alteração, imprima o nome do arquivo e as linhas alteradas para que stderreu possa fazer algo como

find -type f -name 'myfiles' -exec gawk -i inplace '{if(gsub(/pat/, "repl")) { print FILENAME > "/proc/self/fd/2" ; print > "/proc/self/fd/2"; } print;}' {} +

mas existe uma maneira de usar stdoutou uma maneira mais limpa de imprimir esse bloco no fluxo alternativo?


2
Nesse caso em particular, você pode querer executar algo parecido com find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;esse modo. Somente usará o awk para editar os arquivos que realmente contêm linhas que correspondem a esse padrão.
— 8116 don_crissti

@don_crissti Costumo esquecer o quanto mais rápido greppode ser. Meu primeiro instinto é evitar ter que "processar" o arquivo duas vezes, mas não ficaria surpreso se, de fato, fosse mais rápido. Ele só vai para mostrar por que eu posso confiar em meu intestino em tarefas de perfil
— Eric Renouf

1
Sim, é bastante rápido e lembre-se de que: 1) se não houver correspondência, você processa o arquivo apenas uma vez (a parte com -print -exec gawknão é mais executada) e 2) para na 1ª partida, a menos que a 1ª partida esteja no última linha, você ainda não está processando o arquivo inteiro duas vezes (é mais parecido com 1.X vezes). Além disso, se gawk -i inplaceobras como sed -iele vai editar o arquivo no local de qualquer maneira - timestamps de atualização ou seja, inode etc mesmo se não havia nada para editar ...
— don_crissti

Respostas:


13

Você deve usar /dev/stderrou em /dev/fd/2vez de /proc/self/fd/2. gawkmanipula /dev/fd/xe /dev/stderrpor si só (independentemente de o sistema ter esses arquivos ou não).

Quando você faz um:

print "x" > "/dev/fd/2"

gawkfaz a write(2, "x\n"), enquanto quando você faz:

print "x" > "/proc/self/fd/2"

desde que não trate /proc/self/fd/xespecialmente, faz um:

fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC);
write(fd, "x\n");

Primeiro, /proc/self/fdé específico do Linux e, no Linux, eles são problemáticos. As duas versões acima não são equivalentes quando stderr é um arquivo normal ou outro buscável ou um soquete (para o qual o último falharia) (sem mencionar que desperdiça um descritor de arquivo).

Dito isto, se você precisar gravar no stdout original, precisará salvá-lo em outro arquivo como:

gawk -i inplace '{
   print "goes into the-file"
   print "to stdout" > "/dev/fd/3"}' the-file 3>&1

gawkredireciona o stdout com o local para o arquivo. É necessário porque, por exemplo, você deseja:

awk -i inplace '{system("uname")}' file

para armazenar a unamesaída no file.


2

Apenas por diversão, uma abordagem alternativa usando apenas POSIX dispõe de find, sh, grepe (principalmente) ex:

find . -type f -name 'myfiles' -exec sh -c '
  for f do grep -q "pat" "$f" &&
    { printf "%s\n" "$f";
      printf "%s\n" "%s/pat/repl/g" x | ex "$f";
  }; done' find-sh {} +

(Todas as quebras de linha no comando acima são opcionais; podem ser condensadas em uma linha.)

Ou, sem dúvida mais legível:

find . -type f -name 'myfiles' -exec sh -c '
  for f
  do
    if grep -q "pat" "$f"; then
      printf "%s\n" "$f"
      printf "%s\n" "%s/pat/repl/g" x | ex "$f"
    fi
  done' find-sh {} +

:)


(Este comando não foi testado; as edições são bem-vindas se eu fizer alguma brincadeira.)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.