Bagaimana cara menerapkan tindakan awk yang sama ke file yang berbeda?

8

Saya baru awk dan saya tidak tahu apakah mungkin menulis skrip awk yang melakukan ini:

Saya memiliki ratusan file data yang harus saya sortir. Untuk masing-masing saya menggunakan satu-liner berikut:

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

dan saya mendapatkan output yang saya butuhkan. Namun saya ingin memiliki skrip untuk mengotomatiskan tindakan ini, mengambil setiap file, menerapkan tindakan dan menulis file yang diurutkan yang sesuai.

Saya sangat menghargai bantuan Anda!

Nacu
sumber

Jawaban:

7

Jika Anda memodifikasi awkkode, dapat diselesaikan dengan satu awkproses dan tidak ada loop shell:

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

Bukan kecantikan, hanya lebih cepat tidak penting.

Penjelasan seperti yang diminta dalam komentar.

FNR( f ile n umber atau r ecord) mirip dengan NR( n umber atau r ecord), tetapi meskipun NRnomor urut yang berkelanjutan dari semua rekaman input, FNRdiatur ulang ke 1 saat pemrosesan file input baru dimulai.

Sebuah gawk4.0-satunya alternatif untuk FNR==1adalah BEGINFILEpola khusus.

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
sumber
Terima kasih @manatwork! Itu luar biasa. Tidak seperti jawaban terakhir, saya tidak mengerti persis bagaimana cara kerja satu garis ini, tetapi ternyata berhasil. Jika Anda punya waktu, saya akan berterima kasih jika Anda bisa menjelaskan kepada saya apa yang FNR==1dilakukannya. =)
Nacu
12

Anda dapat menerapkan file dalam for for:

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

Atau di satu baris:

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

Karena Anda tidak menentukan shell yang mana, basenamegunakan yang lebih standar daripada menggunakan sintaksis khusus shell ${file%%.tex}.

Arcege
sumber
1
"Sintaks khusus-shell" itu ada dalam POSIX dan tersedia di hampir setiap sistem unix yang masih dalam garansi, dan banyak yang tidak.
Gilles 'SO- stop being evil'
Terima kasih @Arcege !, Saya menggunakan emacs sebagai shell. Meskipun saran Anda cukup dimengerti, saya tidak tahu bagaimana menggunakannya. Sejauh yang saya mengerti dan saya telah berlatih, seseorang menulis skrip .awk yang Anda jalankan sebelum file atau folder yang ingin Anda terapkan. Apakah saya benar? Saya melakukan itu, namun ini sepertinya jenis naskah lain yang saya tidak tahu cara menggunakannya.
Nacu
Anda dapat menjalankan shell di dalam emacs (<kbd> Mx </kbd> shell) dan menjalankan perintah di atas di dalam itu pada prompt. Atau buka terminal dan jalankan perintah di sana. Ada dua cara untuk menentukan skrip (awk, shell, dll): baik di baris perintah atau dalam file. awkPerintah Anda dalam posting menggunakan formulir baris perintah; perintah "satu baris" saya juga merupakan bentuk baris perintah.
Arcege
0

Pertanyaan lama tetapi mengingat bahwa terakhir kali saya melihat satu komputer pribadi inti adalah satu dekade lalu, Anda dapat menggunakan gnu paralel

Untuk mengatasi ekspansi shell dan interpretasi kutipan

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

Gunakan glob yang tepat untuk memilih file input. Di sini saya menggunakan {.} untuk mengambil ekstensi dari nama output karena saya menambahkannya setelah itu

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

di mana Xjumlah prosesor yang ingin Anda gunakan, Anda masih dapat menggunakan 1. Ini akan memberi Anda file[1-9]_sorted.texsebagai output

matrs
sumber