¿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!

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

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}.


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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.