¿Cómo aplicar la misma acción awk a diferentes archivos?

8

Soy nuevo en awk y no sé si es posible escribir un script awk que haga esto:

Tengo cientos de archivos de datos que tengo que ordenar. Para cada uno uso el siguiente one-liner:

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

y obtengo la salida que necesito. Sin embargo, me gustaría tener un script para automatizar esta acción, tomar cada archivo, aplicar la acción y escribir el archivo ordenado correspondiente.

¡Apreciaría tu ayuda!

Nacu
fuente

Respuestas:

7

Si modifica el awkcódigo, puede resolverse mediante un solo awkproceso y sin bucle de shell:

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

No es una belleza, solo que insignificantemente más rápido.

Explicaciones según lo solicitado en comentario.

FNR( F ile n umber o r ECORD) es similar a NR( n umber o r ECORD), pero mientras que NRes un número de secuencia continua de todos los registros de entrada, FNRse pone a 1 cuando el procesamiento de un nuevo archivo de entrada se ha iniciado.

Una gawkúnica alternativa 4.0 para el FNR==1es el BEGINFILEpatrón 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
hombre trabajando
fuente
Gracias @manatwork! Eso fue asombroso. A diferencia de la última respuesta, no entiendo exactamente cómo funciona esta frase, pero funcionó. Si tiene tiempo, le agradecería que me explicara qué hace FNR==1. =)
Nacu
12

Puede aplicar los archivos en un bucle for:

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

O en una línea:

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

Dado que no especifica qué shell, vaya con el estándar más en su basenamelugar utilizando la sintaxis específica del shell ${file%%.tex}.

Arcege
fuente
1
Esa "sintaxis específica de shell" está en POSIX y está disponible en prácticamente todos los sistemas Unix que todavía están en garantía, y muchos que no lo están.
Gilles 'SO- deja de ser malvado'
¡Gracias @Arcege !, uso emacs como shell. Aunque su sugerencia es bastante comprensible, no sé cómo usarla. Hasta donde yo entiendo y he sido practicado, uno escribe un script .awk que ejecuta antes del archivo o carpeta al que desea aplicarlo. Estoy en lo cierto? Lo hice, sin embargo, este parece otro tipo de script que no sé cómo usar.
Nacu
Puede ejecutar un shell dentro de emacs (<kbd> Mx </kbd> shell) y ejecutar los comandos anteriores dentro de eso en el indicador. O abra una terminal y ejecute el comando allí. Hay dos formas de especificar scripts (awk, shell, etc.): en la línea de comandos o en un archivo. Su awkcomando en la publicación utiliza el formulario de línea de comandos; mi comando de "una línea" también es un formulario de línea de comandos.
Arcege
0

Antigua pregunta, pero dado que la última vez que vi una computadora personal de un solo núcleo fue hace una década, puedes usar GNU paralelo

Para resolver la expansión de shell e interpretación de citas

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

Use el globo apropiado para seleccionar los archivos de entrada. Aquí estoy usando {.} para sacar la extensión del nombre de salida porque la agrego después

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

¿Dónde Xestá la cantidad de procesadores que desea usar? Todavía puede usar 1. Esto le daría file[1-9]_sorted.texcomo salidas

matrs
fuente