Cách tốt nhất để đưa một phân đoạn ra khỏi tệp văn bản là gì?


Câu trả lời:


12

bạn có thể thử:

cat textfile | head -n 45 | tail -n 26

hoặc là

cat textfile | awk "20 <= NR && NR <= 45" 

cập nhật:

Như Mahomedalid đã chỉ ra, catkhông cần thiết và hơi dư thừa, nhưng nó làm cho một lệnh sạch, dễ đọc.

Nếu catlàm phiền bạn, một cách giải quyết tốt hơn sẽ là:

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfilehoạt động quá, và đọc dễ dàng.
ephemient

Tôi thích việc sử dụng stdin hơn, nó có tính nhất quán toàn cầu với phần còn lại của nix
Stefan

1
Đọc từ các đối số dòng lệnh cũng có tính nhất quán với các tiện ích UNIX khác và điểm chính của tôi là thể hiện ,toán tử phạm vi của awk .
ephemient

lol, ý tôi là @adam. nhưng vâng, tôi thích đề xuất của bạn
Stefan

Tôi nghĩ câu trả lời của @ ephemient là câu trả lời hay nhất ở đây. Mặt khác, các lệnh khá khó hiểu.
Léo Léopold Hertz

13

Thậm chí đơn giản hơn:

sed -n '20,45p;45q' < textfile

Cờ -n vô hiệu hóa đầu ra mặc định. Bao gồm các địa chỉ "20,45" từ 20 đến 45. Lệnh "p" in dòng hiện tại. Và q thoát ra sau khi in dòng.


1
+1 đẹp, tôi thích, nhưng dòng 20 đến 45 :)
Stefan

1
ok ok, tôi đã chỉnh sửa nó để nói 20,45 :-)
dkagedal

Việc xóa qlệnh (mọi thứ bắt đầu từ ;) đã cải thiện hiệu suất cho tôi khi trích xuất một dòng 26995107 từ tệp 27169334.
Ruslan

6

Đây không phải là một câu trả lời nhưng không thể đăng nó như một bình luận.

Một cách khác (rất nhanh) để làm điều đó đã được mikeerv đề xuất ở đây :

{ head -n 19 >/dev/null; head -n 26; } <infile

Sử dụng cùng một tệp kiểm tra như ở đây và cùng một quy trình, đây là một số điểm chuẩn (trích xuất các dòng 1000020-1000045):

mikeerv :

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

Stefan :

head iplist -n 1000045 | tail -n 26

real    0m0.054s

Đây là những giải pháp nhanh nhất và sự khác biệt là không đáng kể (cho một lần vượt qua) (tôi đã thử với các phạm vi khác nhau: một vài dòng, hàng triệu dòng, v.v.).

Tuy nhiên, làm điều đó mà không có đường ống có thể mang lại một lợi thế đáng kể cho một ứng dụng cần tìm kiếm trên nhiều phạm vi dòng theo cách tương tự, như:

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

... mà in ...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

... và chỉ đọc tệp qua một lần.


Các sed/ awk/ perlgiải pháp khác đọc toàn bộ tệp và vì đây là về các tệp lớn, nên chúng không hiệu quả lắm. Tôi đã ném vào một số lựa chọn thay thế exithoặc quit sau dòng cuối cùng trong phạm vi được chỉ định:

Stefan :

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

so với

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedal ( sed):

sed -n 1000020,1000045p iplist

real    0m0.947s

so với

sed '1,1000019d;1000045q' iplist

real    0m0.143s

Steven D :

perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

so với

perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s

+1 Tôi nghĩ rằng đây là câu trả lời tốt nhất ở đây! Sẽ thật tuyệt nếu có được bao nhiêu thời gian với điều này awk NR==1000020,NR==1000045 textfiletrong hệ thống của bạn.
Léo Léopold Hertz

3
ruby -ne 'print if 20 .. 45' file

1
một đồng nghiệp rubyist, bạn nhận được phiếu bầu của tôi thưa ngài
Stefan

1
Trong khi chúng ta đang ở đó, tại sao không python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'quá? :-P Đây là điều mà Ruby, được mô phỏng theo Perl, lấy cảm hứng từ awk / sed, có thể thực hiện dễ dàng.
ephemient

2

Vì sed và awk đã được sử dụng, đây là một giải pháp perl:

perl -nle "print if ($. > 19 && $. < 46)" < textfile

Hoặc, như được chỉ ra trong các ý kiến:

perl -ne 'print if 20..45' textfile

2
Những gì với tất cả những nhân vật phụ? Không cần phải bóc tách và thêm lại dòng mới, flip-flop giả định so sánh với số dòng và toán tử kim cương chạy qua các đối số nếu được cung cấp. perl -ne'print if 20..45' textfile
ephemient

1
Đẹp. -nle là một chút của một phản xạ tôi cho rằng, đối với phần còn lại, tôi không có lý do gì để cứu sự thiếu hiểu biết.
Steven D
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.