Como aplicar a mesma ação awk a arquivos diferentes?

8

Eu sou novo no awk e não sei se é possível escrever um script do awk que faça isso:

Eu tenho centenas de arquivos de dados que tenho que classificar. Para cada um, eu uso a seguinte linha:

awk 'ORS=NR%3?" ":"\n" ' file1.tex >  file1_sorted.tex
awk 'ORS=NR%3?" ":"\n" ' file2.tex >  file2_sorted.tex
...

e recebo a saída que preciso. No entanto, eu gostaria de ter um script para automatizar essa ação, pegando cada arquivo, aplicando a ação e escrevendo o arquivo classificado correspondente.

Gostaria muito de receber sua ajuda!

Nacu
fonte

Respostas:

7

Se você modificar o awkcódigo, poderá ser resolvido por um único awkprocesso e sem loop de shell:

awk 'FNR==1{if(o)close(o);o=FILENAME;sub(/\.tex/,"_sorted.tex",o)}{ORS=FNR%3?" ":"\n";print>o}' *.tex

Não é uma beleza, apenas insignificantemente mais rápido.

Explicações, conforme solicitado no comentário.

FNR( F ile n úmero ou r ecord) é semelhante ao NR( n úmero ou r ecord), mas ao mesmo tempo NRé um número de sequência contínua de todos os registos de entrada, FNRé reposto a 1 quando o processamento de um novo ficheiro de entrada é iniciado.

Uma gawkúnica alternativa 4.0 para o FNR==1é o BEGINFILEpadrão especial.

awk '
FNR==1{   # first record of an input file?
  if(o)close(o);   # was previous output file? close it
  o=FILENAME;sub(/\.tex/,"_sorted.tex",o)   # new output file name
}
{
  ORS=FNR%3?" ":"\n";   # set ORS based on FNR (not NR as in the original code)
  print>o   # print to the current output file
}
' *.tex
homem a trabalhar
fonte
Obrigado @manatwork! Isso foi demais. Ao contrário da última resposta, não entendi exatamente como essa linha única funciona, mas funcionou. Se você tiver tempo, eu agradeceria se você pudesse me explicar o que FNR==1faz. =)
Nacu
12

Você pode aplicar os arquivos em um loop for:

for file in *.tex;
do
    awk 'ORS=NR%3?" ":"\n"' "$file" > "$(basename "$file")_sorted.tex"
done

Ou em uma linha:

for file in *.tex; do awk 'ORS=NR%3?" ":"\n"' $file > "$(basename "$file" .tex)_sorted.tex"; done

Como você não especifica qual shell, basenameuse o mais padrão, usando a sintaxe específica do shell ${file%%.tex}.

Arcege
fonte
1
Essa "sintaxe específica do shell" está no POSIX e está disponível em praticamente todos os sistemas unix que ainda estão na garantia e muitos que não estão.
Gilles 'SO- stop be evil'
Obrigado @Arcege !, eu uso o emacs como shell. Embora sua sugestão seja bastante compreensível, não sei como usá-la. Tanto quanto eu entendi e tenho praticado, escreve-se um script .awk que você executa antes do arquivo ou pasta em que deseja aplicá-lo. Estou certo? Eu fiz isso, no entanto, este parece outro tipo de script que eu não sei usar.
Nacu
Você pode executar um shell no emacs (<kbd> Mx </kbd> shell) e executar os comandos acima dentro do prompt. Ou abra um terminal e execute o comando lá. Há duas maneiras de especificar scripts (awk, shell, etc): na linha de comando ou em um arquivo. Seu awkcomando na postagem usa o formulário da linha de comandos; meu comando "uma linha" também é um formulário de linha de comando.
Arcege 20/02/2012
0

Pergunta antiga, mas como a última vez que vi um computador pessoal com um único núcleo foi uma década atrás, você pode usar o gnu paralelo

Para resolver a expansão shell e interpretação de citações

my_awk='ORS=NR%3?" ":"\n"' 

Use a glob adequada para selecionar os arquivos de entrada. Aqui estou usando {.} para remover a extensão do nome da saída, porque depois a anexo

parallel -jX "awk '$my_awk' {} > {.}_sorted.tex" ::: *.tex

onde Xestá o número de processadores que você deseja usar, ainda assim você pode usar 1. Isso forneceria file[1-9]_sorted.texcomo saídas

matrs
fonte