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.