Lệnh sẽ chỉ in giá trị một lần mặc dù nó xuất hiện nhiều lần


8

Tôi có một tệp txt lớn trong đó các giá trị đang lặp lại nhiều lần. Có một số lệnh mà tôi có thể sử dụng sẽ đi qua tệp và nếu một giá trị xuất hiện một lần không lặp lại?

SO4
HOH
CL
BME
HOH
SO4
HOH
CL
BME
HOH
SO4
HOH
SO4
HOH
CL
BME
HOH
SO4
HOH
CL
BME
HOH
CL

Vì vậy, nó sẽ trông giống như thế này:

S04   
HOH  
CL   
BME 

Vấn đề là tôi có số lượng lớn các giá trị khác nhau, vì vậy không thể thực hiện thủ công như ở đây.

Câu trả lời:


11

Bạn có thể sử dụng lệnh sortvới tùy chọn --unique:

sort -u input-file

Nếu bạn muốn ghi kết quả vào TẬP_TIN thay vì đầu ra tiêu chuẩn, hãy sử dụng tùy chọn --output=FILE:

sort -u input-file -o output-file

Lệnh uniqcũng có thể được áp dụng. Trong trường hợp này, các dòng giống hệt nhau phải là hệ quả, do đó, đầu vào phải được sắp xếp sơ bộ - cảm ơn @RonJohn cho ghi chú này :

sort input-file | uniq > output-file

Tôi thích sortlệnh cho các trường hợp tương tự, vì tính đơn giản của nó, nhưng nếu bạn làm việc với các mảng lớn, awkcách tiếp cận từ câu trả lời của John1024 có thể mạnh mẽ hơn. Dưới đây là so sánh thời gian giữa các phương pháp được đề cập, được áp dụng trên một tệp (dựa trên ví dụ trên) với gần 5 triệu dòng:

$ cat input-file | wc -l
20000000

$ TIMEFORMAT=%R
$ time sort -u input-file | wc -l
64
7.495

$ time sort input-file | uniq | wc -l
64
7.703

$ time awk '!a[$0]++' input-file | wc -l      # from John1024's answer
64
1.271

$ time datamash rmdup 1 < input-file | wc -l  # from αғsнιη's answer
64
0.770

Sự khác biệt quan trọng khác được đề cập bởi @Ruslan :

sort -usẽ chỉ in kết quả sau khi đầu vào kết thúc, trong khi awklệnh này sẽ in từng dòng kết quả mới một cách nhanh chóng (điều này có thể quan trọng hơn đối với đầu vào đường ống so với tệp).

Đây là một minh họa:

nhập mô tả hình ảnh ở đây

Trong ví dụ trên, vòng lặp (hiển thị bên dưới) tạo ra 500 kết hợp ngẫu nhiên, mỗi kết hợp có độ dài ba ký tự, của các chữ cái AD. Những kết hợp này được dẫn đến awkhoặc sort.

for i in {1..500}; do cat /dev/urandom | tr -dc A-D | head -c 3; echo; done

1
Đó là lệnh rất đơn giản! Cảm ơn nhiều! Tất cả tốt nhất.
djordje

2
Ồ, trong những ngày mà một tiện ích đã làm một việc và làm tốt !! sort input-file | uniq!!!!
RonJohn

15

Nếu bạn muốn giữ các dòng đầu ra theo thứ tự như các dòng đầu vào, hãy sử dụng:

$ awk '!a[$0]++' file
SO4
HOH
CL
BME

Làm thế nào nó hoạt động:

Điều này sử dụng mảng kết hợp ađể đếm số lần mỗi dòng đã được nhìn thấy trước đó. Nếu nó chưa được nhìn thấy trước đó, dòng được in.


2
Nó là rất khó khăn với awk, nhưng sort -ulà cách dễ dàng.
Pierre François

4
@ PierreFrançois, nhưng sort -ucũng là cách chậm nhất :) Tôi đã cập nhật câu trả lời của mình với so sánh thời gian giữa hai cách tiếp cận.
pa4080

4
Ngoài ra, sort -usẽ chỉ in kết quả sau khi đầu vào kết thúc, trong khi awklệnh này sẽ in từng dòng kết quả mới một cách nhanh chóng (điều này có thể quan trọng hơn đối với đầu vào đường ống so với tệp).
Ruslan

Cảm ơn bạn đã lưu ý, @Ruslan! Tôi đã cố gắng minh họa nó trong câu trả lời của tôi.
pa4080

Tôi phải thú nhận rằng awkgiải pháp này là một giải pháp rất tốt, mặc dù không dễ đọc như sort.
Pierre François

1

Bạn cũng có thể sử dụng GNU datamash ở đây như sau và sẽ giữ thứ tự dòng.

datamash rmdup 1 < infile

1
Theo time so sánh đây là giải pháp nhanh nhất, được cung cấp ở đây.
pa4080
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.