Làm thế nào để chia một tập tin lớn thành hai phần, tại một mẫu?
Cho một ví dụ file.txt:
ABC
EFG
XYZ
HIJ
KNL
Tôi muốn tách tệp này XYZsao cho file1có chứa các dòng lên đến XYZvà phần còn lại của các dòng trong file2.
Làm thế nào để chia một tập tin lớn thành hai phần, tại một mẫu?
Cho một ví dụ file.txt:
ABC
EFG
XYZ
HIJ
KNL
Tôi muốn tách tệp này XYZsao cho file1có chứa các dòng lên đến XYZvà phần còn lại của các dòng trong file2.
Câu trả lời:
Với awkbạn có thể làm:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
Giải thích: Đối awksố đầu tiên ( out=file1) xác định một biến có tên tệp sẽ được sử dụng cho đầu ra trong khi đối số tiếp theo ( largefile) được xử lý. Các awkchương trình sẽ in tất cả các dòng vào một file nào bởi biến out( {print >out}). Nếu mẫu XYZđược tìm thấy, biến đầu ra sẽ được xác định lại để trỏ đến tệp mới ( {out="file2}") sẽ được sử dụng làm mục tiêu để in các dòng dữ liệu tiếp theo.
Người giới thiệu:
Đây là một công việc cho csplit:
csplit -sf file -n 1 large_file /XYZ/
sẽ sphân chia tập tin một cách bất hợp pháp, tạo ra các phần có trước fix filevà được nđánh số bằng một chữ số duy nhất, file0v.v. Lưu ý rằng việc sử dụng /regex/sẽ chia ra, nhưng không bao gồm dòng phù hợp regex. Để phân tách tối đa và bao gồm cả khớp dòng, regexthêm phần +1bù:
csplit -sf file -n 1 large_file /XYZ/+1
Điều này tạo ra hai tập tin, file0và file1. Nếu bạn thực sự cần đặt tên chúng file1và file2bạn luôn có thể thêm một mẫu trống vào csplitlệnh và xóa tệp đầu tiên:
csplit -sf file -n 1 large_file // /XYZ/+1
tạo ra file0, file1và file2nhưng file0là trống để bạn có thể loại bỏ nó một cách an toàn:
rm -f file0
Với một hiện đại, kshđây là một biến thể vỏ (tức là không có sed) của một trong những sedcâu trả lời dựa trên:
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
Và một biến thể khác trong kshmột mình (tức là cũng bỏ qua cat):
{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1
( kshGiải pháp thuần túy dường như khá hiệu quả; trên tệp thử nghiệm 2,4 GB, nó cần 19-21 giây, so với 39-47 giây với phương pháp sed/ catdựa trên).
readvà print- bạn chỉ nên để nó tự xuất ra. Hiệu suất sẽ tốt hơn nếu bạn xây dựng bộ công cụ AST hoàn toàn và có được tất cả các kshnội dung được biên dịch trong - thực sự kỳ lạ đối với tôi đó sedkhông phải là một trong số chúng. Nhưng với những thứ như while <file dotôi đoán bạn không cần sednhiều như vậy ...
awkthực hiện trong điểm chuẩn của bạn? Và mặc dù tôi khá chắc chắn kshsẽ luôn chiến thắng trong cuộc chiến này, nhưng nếu bạn đang sử dụng GNU thì sedbạn không công bằng lắm sed- -unbuffered của GNU là một cách tiếp cận kém cỏi đối với POSIXLY để đảm bảo phần bù của bộ mô tả bị bỏ lại khi chương trình thoát khỏi nó - không cần phải làm chậm hoạt động thường xuyên của chương trình - bộ đệm vẫn ổn - tất cả những gì sedphải làm là lseek mô tả khi kết thúc. Vì lý do gì GNU đảo ngược tâm lý đó.
while ; việc in ấn được thực hiện hoàn toàn như là hiệu ứng phụ được xác định của <##toán tử chuyển hướng. Và chỉ có dòng phù hợp cần in. (Bằng cách đó, việc triển khai tính năng shell là linh hoạt nhất để hỗ trợ inc./excl.) Một whilevòng lặp rõ ràng mà tôi mong đợi sẽ chậm hơn đáng kể (nhưng chưa được kiểm tra).
head thay vì read; có vẻ như chỉ chậm hơn một chút, nhưng đó là mã terser : { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3.
Một cách dễ dàng là in ra STDOUT hoặc STDERR, tùy thuộc vào việc mẫu đích có được khớp hay không. Sau đó, bạn có thể sử dụng các toán tử chuyển hướng của shell để chuyển hướng đầu ra tương ứng. Ví dụ: trong Perl, giả sử tệp đầu vào được gọi fvà hai tệp đầu ra f1và f2:
Loại bỏ dòng phù hợp với mẫu phân chia:
perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2Bao gồm dòng khớp:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2Ngoài ra, in ra các tệp xử lý khác nhau:
Loại bỏ dòng phù hợp với mẫu phân chia:
perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' fBao gồm dòng khớp:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZdòng vào đầu ra hay không?