Làm cách nào để loại bỏ các từ cụ thể khỏi các dòng của tệp văn bản?


13

tập tin văn bản của tôi trông như thế này:

Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341

bây giờ tôi muốn xóa Liquid penetration 95% mass (m)khỏi dòng của mình để chỉ lấy các giá trị. Tôi nên làm thế nào?


3
chỉ đơn giảngrep -o '[^[:space:]]\+$' file
Avinash Raj

@AvinashRaj: Đến thời điểm hiện tại, giải pháp này nhận được 'huy chương putty' :)
pa4080

2
@ pa4080 Ít nhất là đối với đầu vào mà tôi đã thử nghiệm (10 triệu dòng), cách tiếp cận chung của Avinash Raj có thể được thực hiện nhanh hơn bằng cách sử dụng PCRE. (Tôi có thể xác nhận rằng công cụ, không phải mẫu, chịu trách nhiệm, vì GNU grep chấp nhận \S+$với một trong hai -Ehoặc -P.) Vì vậy, loại giải pháp này vốn không chậm. Nhưng tôi vẫn không thể có được nó ở bất cứ đâu gần với phương pháp của αsнιcut , mà cũng đã giành được điểm chuẩn của bạn .
Eliah Kagan

Câu trả lời:


22

Nếu chỉ có một =dấu hiệu, bạn có thể xóa mọi thứ trước đó và bao gồm =như thế này:

$ sed -r 's/.* = (.*)/\1/' file
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

Nếu bạn muốn thay đổi tệp gốc, hãy sử dụng -itùy chọn sau khi kiểm tra:

sed -ri 's/.* = (.*)/\1/' file

Ghi chú

  • -rsử dụng ERE để chúng ta không phải trốn thoát ()
  • s/old/newthay thế oldbằngnew
  • .* bất kỳ số lượng của bất kỳ nhân vật
  • (things)tiết kiệm thingsđể backreference sau với \1, \2vv

Cảm ơn nó đã làm việc. Tôi đã sử dụng lệnh này để ghi đè lên tệp hiện có: sed -i -r 's /.*= (. *) / \ 1 /' time.txt Bạn có thể giải thích nó hoạt động như thế nào không?
OE

Tại sao không tránh được phản ứng ngược? s/^.*= //sẽ hoạt động tốt như nhau, vì giá trị chính xác nằm ở cuối dòng.
jpaugh

@jpaugh Một phần vì đã quá muộn để thay đổi câu trả lời của tôi, đó là câu đầu tiên được đăng - những người khác đã đưa ra giải pháp mà bạn đề cập và các cách hiệu quả khác cho trường hợp này :) Nhưng có lẽ cách hiển thị cách sử dụng \1vv có giá trị đối với những người đáp ứng câu hỏi này khi tìm kiếm, ai không gặp phải vấn đề đơn giản như vậy
Zanna

@Zanna Nó nói chung chung hơn, ít nhất.
jpaugh

21

Đây là một công việc cho awk; giả sử các giá trị chỉ xảy ra trong trường cuối cùng (theo ví dụ của bạn):

awk '{print $NF}' file.txt
  • NFlà một awkbiến, mở rộng đến số lượng các trường trong một bản ghi (dòng), do đó $NF(lưu ý $ở phía trước) chứa giá trị của trường cuối cùng.

Thí dụ:

% cat temp.txt 
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341

% awk '{print $NF}' temp.txt
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

13

Tôi quyết định so sánh các giải pháp khác nhau, được liệt kê ở đây. Với mục đích này, tôi đã tạo một tệp lớn, dựa trên nội dung do OP cung cấp:

  1. Tôi đã tạo một tập tin đơn giản, có tên input.file:

    $ cat input.file
    Liquid penetration 95% mass (m) = 0.000205348
    Liquid penetration 95% mass (m) = 0.000265725
    Liquid penetration 95% mass (m) = 0.000322823
    Liquid penetration 95% mass (m) = 0.000376445
    Liquid penetration 95% mass (m) = 0.000425341
    
  2. Sau đó, tôi thực hiện vòng lặp này:

    for i in {1..100}; do cat input.file | tee -a input.file; done
    
  3. Cửa sổ ga đã bị chặn. Tôi thực hiện killall teetừ một thiết bị đầu cuối khác. Sau đó, tôi kiểm tra nội dung của tệp bằng các lệnh: less input.filecat input.file. Nó trông tốt, ngoại trừ dòng cuối cùng. Vì vậy, tôi đã xóa dòng cuối cùng và tạo một bản sao lưu: cp input.file{,.copy}(vì các lệnh sử dụng tùy chọn inplace ).

  4. Số lượng cuối cùng của các dòng vào tệp input.file2 192 473 . Tôi đã nhận được số đó bằng lệnh wc:

    $ cat input.file | wc -l
    2192473
    

Đây là kết quả của sự so sánh:

  • grep -o '[^[:space:]]\+$'

    $ time grep -o '[^ [: space:]] \ + $' input.file> output.file
    
    số 0m58.539 thật
    người dùng 0m58.416s
    sys 0m0.108s
    
  • sed -ri 's/.* = (.*)/\1/'

    $ time sed -ri 's /.* = (. *) / \ 1 /' input.file
    
    0m26.936s thật
    người dùng 0m22.836s
    hệ thống 0m4.092
    

    Ngoài ra, nếu chúng ta chuyển hướng đầu ra sang một tệp mới, lệnh sẽ nhanh hơn:

    $ time sed -r 's /.* = (. *) / \ 1 /' input.file> output.file
    
    số 0m19.734 thực
    người dùng 0m19.672s
    sys 0m0.056s
    
  • gawk '{gsub(".*= ", "");print}'

    $ time gawk '{gsub (". * =", ""); print}' input.file> output.file
    
    số 0m5.644 thực
    người dùng 0m5.568
    sys 0m0.072s
    
  • rev | cut -d' ' -f1 | rev

    $ thời gian rev input.file | cắt -d '' -f1 | rev> output.file
    
    0m3.703s thực
    người dùng 0m2.108s
    hệ thống 0m4.916
    
  • grep -oP '.*= \K.*'

    $ time grep -oP '. * = \ K. *' input.file> output.file
    
    0m3.328 thực
    người dùng 0m3.252s
    sys 0m0.072s
    
  • sed 's/.*= //' (tương ứng -itùy chọn làm cho lệnh chậm hơn vài lần)

    $ time sed 's /.*= //' input.file> output.file
    
    0m3.310 thực
    người dùng 0m3.212s
    sys 0m0.092s
    
  • perl -pe 's/.*= //' ( -itùy chọn không tạo ra sự khác biệt lớn về năng suất ở đây)

    $ time perl -i.bak -pe 's /.*= //' input.file
    
    số 0m3.187 thực
    người dùng 0m3.128s
    sys 0m0.056s
    
    $ time perl -pe 's /.*= //' input.file> output.file
    
    0m3.138 thực
    người dùng 0m3.036s
    sys 0m0.100s
    
  • awk '{print $NF}'

    $ time awk '{print $ NF}' input.file> output.file
    
    số 0m1.251 thực
    người dùng 0m1.164
    hệ thống 0m0.084
    
  • cut -c 35-

    $ time cut -c 35- input.file> output.file
    
    số 0m0.352 thực
    người dùng 0m0.284
    sys 0m0.064s
    
  • cut -d= -f2

    $ time cut -d = -f2 input.file> output.file
    
    số 0m0.328 thực
    người dùng 0m0.260s
    sys 0m0.064s
    

Nguồn gốc của ý tưởng.


2
vì vậy giải pháp của tôicut -d= -f2 chiến thắng. haha
αғsнιη

Bạn có thể cung cấp thêm thông tin về cách bạn tạo tập tin này? Ngoài ra, làm thế nào để wc -lđầu ra ba số? Khi không có tùy chọn nào khác được thông qua, -ltùy chọn sẽ triệt tiêu mọi thứ trừ số dòng.
Eliah Kagan

@EliahKagan, xong rồi. Tôi đã cập nhật câu trả lời.
pa4080

À, tôi hiểu rồi - không gian là các dấu tách nhóm chữ số. (Có wcthực sự hiển thị các không gian đó không? Có cài đặt ngôn ngữ nào sẽ thực hiện việc đó không?) Cảm ơn đã cập nhật!
Eliah Kagan

@EliahKagan: Cuối cùng tôi đọc câu hỏi của bạn về wcmột lần nữa. Tôi không biết trí thông minh của mình ở đâu sớm hôm nay, nhưng tôi thực sự không thể hiểu chúng. Vì vậy, thực sự các khoảng trắng là dấu phân cách nhóm chữ sốwckhông thêm chúng :)
pa4080

12

Với grep-Pcho có PCRE(Giải thích mô hình như một P erl- C ompatible R egular E xpression) và -omô hình để in phù hợp thôi. Thông \Kbáo sẽ bỏ qua phần phù hợp đến trước chính nó.

$ grep -oP '.*= \K.*' infile
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

Hoặc bạn có thể sử dụng cutlệnh thay thế.

cut -d= -f2 infile

2
Ngoài ra để chạy nhanh nhất trong tất cả các phương pháp thử nghiệm trong chuẩn pa4080 của , các cutphương pháp trong câu trả lời này cũng là người chiến thắng rõ ràng trong một chuẩn mực nhỏ hơn tôi chạy mà phương pháp ít được thử nghiệm nhưng sử dụng một tập tin đầu vào lớn hơn. Nó nhanh hơn gấp mười lần so với biến thể nhanh của phương pháp mà cá nhân tôi thích (và câu trả lời của tôi chủ yếu là về).
Eliah Kagan

11

Vì tiền tố dòng luôn có cùng độ dài (34 ký tự), bạn có thể sử dụng cut:

cut -c 35- < input.txt > output.txt

6

Đảo ngược nội dung của tệp với rev, dẫn đầu ra vào cutvới khoảng trắng dưới dạng dấu phân cách và 1 làm trường đích, sau đó đảo ngược lại để lấy số gốc:

$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

5

Điều này đơn giản, ngắn gọn và dễ viết, hiểu và kiểm tra, và cá nhân tôi thích nó:

grep -oE '\S+$' file

greptrong Ubuntu , khi được gọi bằng -Ehoặc -P, lấy tốc \s có nghĩa là một ký tự khoảng trắng (trong thực tế thường là một khoảng trắng hoặc tab) và \Scó nghĩa là bất cứ thứ gì không phải là một. Sử dụng bộ định lượng+neo cuối dòng$ , mẫu \S+$khớp với một hoặc nhiều khoảng trống ở cuối dòng . Bạn có thể sử dụng -Pthay vì -E; ý nghĩa trong trường hợp này là giống nhau nhưng một công cụ biểu thức chính quy khác được sử dụng, vì vậy chúng có thể có các đặc tính hiệu suất khác nhau .

Điều này tương đương với giải pháp nhận xét của Avinash Raj (chỉ với một cú pháp gọn hơn, dễ dàng hơn):

grep -o '[^[:space:]]\+$' file

Các phương pháp này sẽ không hoạt động nếu có thể có khoảng trắng sau số. Họ có thể được sửa đổi để họ làm, nhưng tôi thấy không có điểm nào để đi vào đó ở đây. Mặc dù đôi khi hướng dẫn để khái quát hóa một giải pháp để làm việc trong nhiều trường hợp, nhưng nó không thực tế để làm như vậy thường xuyên như mọi người thường nghĩ, bởi vì người ta thường không có cách nào để biết trong số nhiều cách không tương thích khác nhau mà vấn đề cuối cùng có thể cần phải làm được khái quát.


Hiệu suất đôi khi là một cân nhắc quan trọng. Câu hỏi này không quy định rằng đầu vào rất lớn và có thể mọi phương pháp đã được đăng ở đây là đủ nhanh. Tuy nhiên, trong trường hợp tốc độ là mong muốn, đây là một điểm chuẩn nhỏ trên tệp đầu vào mười triệu dòng:

$ perl -e 'print((<>) x 2000000)' file > bigfile
$ du -sh bigfile
439M    bigfile
$ wc -l bigfile
10000000 bigfile
$ TIMEFORMAT=%R
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
819.565
$ time grep -oE '\S+$' bigfile > bigfile.out
816.910
$ time grep -oP '\S+$' bigfile > bigfile.out
67.465
$ time cut -d= -f2 bigfile > bigfile.out
3.902
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
815.183
$ time grep -oE '\S+$' bigfile > bigfile.out
824.546
$ time grep -oP '\S+$' bigfile > bigfile.out
68.692
$ time cut -d= -f2 bigfile > bigfile.out
4.135

Tôi đã chạy nó hai lần trong trường hợp thứ tự có vấn đề (vì đôi khi nó làm cho các nhiệm vụ nặng / nặng) và vì tôi không có sẵn máy mà không làm những thứ khác trong nền có thể làm lệch kết quả. Từ những kết quả đó, tôi kết luận như sau, ít nhất là tạm thời và cho các tệp đầu vào có kích thước tôi đã sử dụng:

  • Ồ Vượt qua -P(để sử dụng PCRE ) thay vì -G(mặc định khi không có phương ngữ nào được chỉ định) hoặc -Eđược thực hiện grepnhanh hơn bằng một thứ tự cường độ. Vì vậy, đối với các tệp lớn, có thể sử dụng lệnh này tốt hơn so với lệnh được hiển thị ở trên:

    grep -oP '\S+$' file
  • Ôi !! Các cutphương pháp trong câu trả lời của αғsнιη , , xuất hiện nhiều theo độ nhanh hơn ngay cả những phiên bản nhanh hơn của con đường của tôi! Đó cũng là người chiến thắng trong điểm chuẩn của pa4080 , bao gồm nhiều phương thức hơn phương pháp này nhưng với đầu vào nhỏ hơn - và đó là lý do tại sao tôi chọn nó, trong tất cả các phương pháp khác, để đưa vào thử nghiệm của tôi. Nếu hiệu suất là quan trọng hoặc các tệp rất lớn, tôi nghĩ nên sử dụng phương pháp của αsнι .cut -d= -f2 filecut

    Điều này cũng đóng vai trò như một lời nhắc nhở rằng không nên quên các tiện ích đơn giản cutpastetiện ích và có lẽ nên được ưu tiên khi áp dụng, mặc dù có những công cụ tinh vi hơn như grepthường được cung cấp dưới dạng giải pháp hàng đầu (và cá nhân tôi quen hơn đối với việc sử dụng).


4

perl- s ubstolarship mẫu /.*= /với chuỗi rỗng //:

perl -pe 's/.*= //' input.file > output.file
perl -i.bak -pe 's/.*= //' input.file
  • Từ perl --help:

    -e program        one line of program (several -e's allowed, omit programfile)
    -p                assume loop like -n but print line also, like sed
    -i[extension]     edit <> files in place (makes backup if extension supplied)
    

sed - thay thế mẫu bằng chuỗi rỗng:

sed 's/.*= //' input.file > output.file

hoặc (nhưng chậm hơn ở trên) :

sed -i.bak 's/.*= //' input.file
  • Tôi đề cập đến phương pháp này, vì nó nhanh hơn vài lần so với câu trả lời của Zanna .

gawk- thay thế mẫu ".*= "bằng chuỗi rỗng "":

gawk '{gsub(".*= ", "");print}' input.file > output.file
  • Từ man gawk:

    gsub(r, s [, t]) For each substring matching the regular expression r in the string t,
                     substitute the string s, and return the number of substitutions. 
                     If t is not supplied, use $0...
    
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.