Làm thế nào để áp dụng cùng một hành động awk cho các tập tin khác nhau?


8

Tôi là người mới trong awk và tôi không biết liệu có thể viết một kịch bản awk thực hiện điều này không:

Tôi có hàng trăm tệp dữ liệu mà tôi phải sắp xếp. Đối với mỗi một tôi sử dụng một lót sau đây:

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

và tôi nhận được đầu ra tôi cần. Tuy nhiên tôi muốn có một kịch bản để tự động hóa hành động này, lấy từng tệp, áp dụng hành động và viết tệp được sắp xếp tương ứng.

Tôi sẽ đánh giá cao sự giúp đỡ của bạn!

Câu trả lời:


7

Nếu bạn sửa đổi awkmã, có thể được giải quyết bằng một awkquy trình duy nhất và không có vòng lặp shell:

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

Không phải là một vẻ đẹp, chỉ là nhanh hơn đáng kể.

Giải thích theo yêu cầu trong bình luận.

FNR( f ile n umber hoặc r ecord) tương tự NR( n umber hoặc r ecord), nhưng trong khi đó NRlà một số thứ tự liên tục của tất cả các bản ghi đầu vào, FNRđược đặt lại thành 1 khi bắt đầu xử lý tệp đầu vào mới.

Một gawkthay thế 4.0 duy nhất cho FNR==1BEGINFILEmô hình đặc biệt.

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

Cảm ơn @manatwork! Điều đó thật tuyệt. Không giống như câu trả lời cuối cùng, tôi không hiểu chính xác cách thức hoạt động của lớp lót này, nhưng nó đã làm. Nếu bạn có thời gian, tôi sẽ cảm ơn bạn nếu bạn có thể giải thích cho tôi những gì FNR==1làm. =)
NAC

12

Bạn có thể áp dụng các tệp trong một vòng lặp for:

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

Hoặc trên một dòng:

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

Vì bạn không chỉ định shell nào, basenamethay vào đó hãy sử dụng cú pháp cụ thể của shell ${file%%.tex}.


1
Đó là cú pháp đặc thù của lớp vỏ cứng trong ứng dụng POSIX và có sẵn trên thực tế mọi hệ thống unix vẫn đang được bảo hành và nhiều hệ thống không được bảo hành.
Gilles 'SO- ngừng trở nên xấu xa'

Cảm ơn @Arcege!, Tôi sử dụng emacs làm vỏ. Mặc dù đề xuất của bạn khá dễ hiểu, tôi không biết cách sử dụng nó. Theo như tôi hiểu và tôi đã được thực hành, người ta viết một tập lệnh .awk mà bạn chạy trước tập tin hoặc thư mục bạn muốn áp dụng nó. Tôi có đúng không Tôi đã làm điều đó, tuy nhiên đây có vẻ là một loại kịch bản khác mà tôi không biết cách sử dụng.
Nacu

Bạn có thể chạy shell bên trong emacs (<kbd> Mx </ kbd> shell) và chạy các lệnh ở trên bên trong đó tại dấu nhắc. Hoặc mở một thiết bị đầu cuối và chạy lệnh ở đó. Có hai cách để chỉ định tập lệnh (awk, shell, v.v.): trên dòng lệnh hoặc trong tệp. awkLệnh của bạn trong bài viết sử dụng hình thức dòng lệnh; lệnh "một dòng" của tôi cũng là một dạng dòng lệnh.
Arcege

0

Câu hỏi cũ nhưng cho rằng lần cuối cùng tôi nhìn thấy một máy tính cá nhân lõi đơn là một thập kỷ trước, bạn có thể sử dụng song song gnu

Để giải quyết việc mở rộng vỏ và giải thích các trích dẫn

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

Sử dụng toàn cầu thích hợp để chọn các tập tin đầu vào. Ở đây tôi đang sử dụng {.} để lấy ra phần mở rộng từ tên đầu ra vì sau đó tôi sẽ thêm nó vào

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

nơi Xlà số bộ vi xử lý bạn muốn sử dụng, bạn vẫn có thể sử dụng 1. Điều này sẽ cung cấp cho bạn file[1-9]_sorted.texnhư đầu ra

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.