Как применить одно и то же действие awk к разным файлам?

8

Я новичок в awk, и я не знаю, возможно ли написать сценарий awk, который делает это:

У меня есть сотни файлов данных, которые я должен отсортировать. Для каждого я использую следующую строку:

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

и я получаю вывод, который мне нужен. Однако я хотел бы иметь скрипт для автоматизации этого действия, принимая каждый файл, применяя действие и записывая соответствующий отсортированный файл.

Буду признателен за вашу помощь!

Nacu
источник

Ответы:

7

Если вы измените awkкод, это может быть решено одним awkпроцессом и без цикла оболочки:

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

Не красавица, просто несущественно быстрее.

Пояснения в соответствии с просьбой в комментарии.

FNR( Е Иль н умбры или г ecord) аналогично NR( п темно - коричневого или г ecord), но в то время как NRнепрерывная последовательность , число всех входных записей, FNRсбрасывается на 1 при обработке нового входного файла запускается.

gawk4.0 единственной альтернативой для FNR==1это BEGINFILEспециальный шаблон.

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
manatwork
источник
Спасибо @manatwork! Это было потрясающе. В отличие от последнего ответа, я не понимаю, как именно работает этот однострочный документ, но он это сделал. Если у вас есть время, я бы поблагодарил вас, если бы вы могли объяснить мне, что делает FNR==1. =)
Наку
12

Вы можете применить файлы в цикле:

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

Или на одной строке:

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

Поскольку вы не указываете, какая оболочка, используйте более стандартный, basenameвместо этого используя специальный синтаксис оболочки ${file%%.tex}.

Arcege
источник
1
Этот «специфичный для оболочки синтаксис» существует в POSIX и доступен практически на всех системах Unix, на которые все еще распространяется гарантия, а на многих нет.
Жиль "ТАК - перестань быть злым"
Спасибо @Arcege !, я использую Emacs в качестве оболочки. Хотя ваше предложение довольно понятно, я не знаю, как его использовать. Насколько я понимаю и я практиковался, каждый пишет скрипт .awk, который вы запускаете перед файлом или папкой, к которой хотите применить его. Я прав? Я сделал это, однако это кажется другим видом сценария, который я не знаю, как использовать.
Наку
Вы можете запустить оболочку внутри emacs (<kbd> Mx </ kbd> shell) и запустить приведенные выше команды в командной строке. Или откройте терминал и выполните команду там. Существует два способа указания скриптов (awk, shell и т. Д.): Либо в командной строке, либо в файле. Ваша awkкоманда в публикации использует форму командной строки; моя команда "одна строка" также является формой командной строки.
Arcege
0

Старый вопрос, но, учитывая, что в последний раз, когда я видел одноядерный персональный компьютер десять лет назад, вы можете использовать GNU параллельно

Чтобы решить расширение оболочки и интерпретации кавычек

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

Используйте правильный шарик, чтобы выбрать входные файлы. Здесь я использую, {.} чтобы удалить расширение из выходного имени, потому что я добавляю его позже

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

где Xчисло процессоров, которые вы хотите использовать, все же вы можете использовать 1. Это даст вам в file[1-9]_sorted.texкачестве выходных данных

matrs
источник