Tìm các dòng trùng lặp trong một tệp và đếm xem mỗi dòng được nhân đôi bao nhiêu lần?


529

Giả sử tôi có một tệp tương tự như sau:

123 
123 
234 
234 
123 
345

Tôi muốn tìm xem có bao nhiêu lần '123' được nhân đôi, bao nhiêu lần '234' được sao chép, v.v ... Thật lý tưởng, đầu ra sẽ như sau:

123  3 
234  2 
345  1

4
Bạn muốn sử dụng ngôn ngữ nào?
VMAtm

Câu trả lời:


791

Giả sử có một số trên mỗi dòng:

sort <file> | uniq -c

Bạn cũng có thể sử dụng --countcờ dài hơn với phiên bản GNU, ví dụ: trên Linux:

sort <file> | uniq --count

3
Đây là những gì tôi làm tuy nhiên về mặt thuật toán, đây dường như không phải là cách tiếp cận hiệu quả nhất (O (n log n) * avg_line_len trong đó n là số dòng). Tôi đang làm việc trên các tệp có dung lượng lớn vài gigabyte, vì vậy hiệu suất là vấn đề chính. Tôi tự hỏi liệu có một công cụ nào chỉ đếm trong một lần sử dụng cây tiền tố (trong trường hợp của tôi thường có tiền tố chung) hoặc tương tự, nên thực hiện thủ thuật trong O (n) * avg_line_len. Có ai biết một công cụ dòng lệnh như vậy?
Droggl

21
Một bước bổ sung là chuyển đầu ra của lệnh đó thành lệnh 'sort -n' cuối cùng. Điều đó sẽ sắp xếp kết quả theo đó các dòng xảy ra thường xuyên nhất.
samoz

79
Nếu bạn muốn chỉ in các dòng trùng lặp, hãy sử dụng 'uniq -d'
DmitrySandalov

6
Nếu bạn muốn sắp xếp lại kết quả, bạn có thể sử dụng sortlại như sau:sort <file> | uniq -c | sort -n
Abhishek Kashyap

413

Điều này sẽ chỉ in các dòng trùng lặp , với số lượng:

sort FILE | uniq -cd

hoặc, với các tùy chọn dài GNU (trên Linux):

sort FILE | uniq --count --repeated

trên BSD và OSX, bạn phải sử dụng grep để lọc ra các dòng duy nhất:

sort FILE | uniq -c | grep -v '^ *1 '

Đối với ví dụ đã cho, kết quả sẽ là:

  3 123
  2 234

Nếu bạn muốn in số lượng cho tất cả các dòng, kể cả những dòng chỉ xuất hiện một lần:

sort FILE | uniq -c

hoặc, với các tùy chọn dài GNU (trên Linux):

sort FILE | uniq --count

Đối với đầu vào đã cho, đầu ra là:

  3 123
  2 234
  1 345

Để sắp xếp đầu ra với các dòng thường xuyên nhất ở trên, bạn có thể làm như sau (để có được tất cả kết quả):

sort FILE | uniq -c | sort -nr

hoặc, để chỉ nhận các dòng trùng lặp, thường xuyên nhất trước tiên:

sort FILE | uniq -cd | sort -nr

trên OSX và BSD, cái cuối cùng trở thành:

sort FILE | uniq -c | grep -v '^ *1 ' | sort -nr

1
Điểm tốt với tùy chọn - lặp lại hoặc -d. Vì vậy, chính xác hơn nhiều so với sử dụng "| grep 2" hoặc tương tự!
Lauri

Làm cách nào tôi có thể sửa đổi lệnh này để truy xuất tất cả các dòng có số lần lặp lại lớn hơn 100?
Black_Rider

@Black_Rider Thêm | sort -nhoặc | sort -nrvào đường ống sẽ sắp xếp đầu ra theo số lần lặp lại (tăng dần hoặc giảm dần tương ứng). Đây không phải là những gì bạn đang hỏi nhưng tôi nghĩ nó có thể giúp ích.
Andrea

1
@Black_Rider awk dường như có thể thực hiện tất cả các loại tính toán: trong trường hợp của bạn, bạn có thể làm| awk '$1>100'
Andrea

4
@fionbio Có vẻ như bạn không thể sử dụng -c và -d cùng nhau trên OSX uniq . Cảm ơn đã chỉ ra. Bạn có thể sử dụng grep để lọc ra các dòng duy nhất :sort FILE | uniq -c | grep -v '^ *1 '
Andrea

72

Để tìm và đếm các dòng trùng lặp trong nhiều tệp, bạn có thể thử lệnh sau:

sort <files> | uniq -c | sort -nr

hoặc là:

cat <files> | sort | uniq -c | sort -nr

30

Thông qua :

awk '{dups[$1]++} END{for (num in dups) {print num,dups[num]}}' data

Trong awk 'dups[$1]++'lệnh, biến $1giữ toàn bộ nội dung của cột1 và dấu ngoặc vuông là truy cập mảng. Vì vậy, đối với mỗi cột đầu tiên của dòng trong datatệp, nút của mảng có tên dupsđược tăng lên.

Và cuối cùng, chúng ta sẽ lặp qua dupsmảng với numbiến và in các số đã lưu trước sau đó số lượng giá trị trùng lặp của chúng theo dups[num].

Lưu ý rằng tệp đầu vào của bạn có khoảng trắng ở cuối một số dòng, nếu bạn xóa những dòng đó, bạn có thể sử dụng $0thay cho $1lệnh trên :)


1
Đây không phải là một chút quá mức cần thiết mà chúng ta có uniqsao?
Nathan Fellman

9
sort | uniqvà giải pháp awk có sự đánh đổi hiệu suất & tài nguyên khá khác nhau: nếu các tệp lớn và số lượng dòng khác nhau nhỏ, giải pháp awk hiệu quả hơn rất nhiều. Nó là tuyến tính trong số lượng dòng và sử dụng không gian là tuyến tính trong số lượng dòng khác nhau. OTOH, giải pháp awk cần giữ tất cả các dòng khác nhau trong bộ nhớ, trong khi sắp xếp (GNU) có thể dùng đến các tệp tạm thời.
Lars Noschinski

14

Trong các cửa sổ sử dụng "Windows PowerShell", tôi đã sử dụng lệnh được đề cập dưới đây để đạt được điều này

Get-Content .\file.txt | Group-Object | Select Name, Count

Ngoài ra, chúng ta có thể sử dụng Cmdlet của đối tượng where để lọc kết quả

Get-Content .\file.txt | Group-Object | Where-Object { $_.Count -gt 1 } | Select Name, Count

bạn có thể xóa tất cả các lần xuất hiện của các bản sao ngoại trừ lần xuất hiện cuối cùng ... mà không thay đổi thứ tự sắp xếp của tệp không?
jparram

6

Giả sử bạn đã có quyền truy cập vào hệ vỏ Unix và / hoặc môi trường cygwin tiêu chuẩn:

tr -s ' ' '\n' < yourfile | sort | uniq -d -c
       ^--space char

Về cơ bản: chuyển đổi tất cả các ký tự khoảng trắng thành các ngắt dòng, sau đó sắp xếp đầu ra được đặt và cung cấp dữ liệu đó thành uniq và đếm các dòng trùng lặp.

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.