2009-06-04 26 views
17

Tôi có một tập tin văn bản đơn giản bằng lời nói, được phân cách bởi dấu phẩy, ví dụ:Làm thế nào để xóa từ trùng lặp từ một tập tin văn bản đơn giản sử dụng lệnh linux

word1, word2, word3, word2, word4, word5, word 3, word6, word7, word3 

tôi muốn xóa các bản sao và để trở thành :

word1, word2, word3, word4, word5, word6, word7 

Bất kỳ ý tưởng nào? Tôi nghĩ, egrep có thể giúp tôi, nhưng tôi không chắc chắn, làm thế nào để sử dụng nó chính xác ....

+1

Bạn có muốn các từ là duy nhất trên cơ sở đường hoặc trên toàn bộ tệp không? Ngoài ra, bạn có muốn duy trì thứ tự ban đầu của các từ hoặc bạn có hài lòng nếu đơn đặt hàng bị thay đổi không? – Beano

+0

tôi cần các từ uniq trong toàn bộ tập tin. thứ tự của các từ không quan trọng. – cupakob

+0

Xem thêm: [Làm thế nào tôi có thể tìm các từ lặp lại trong một tệp bằng grep/egrep?] (Http://stackoverflow.com/q/33396629/562769) –

Trả lời

28

Giả sử rằng các từ là một trong mỗi dòng, và các tập tin đã được sắp xếp:

uniq filename 

Nếu file không được sắp xếp:

sort filename | uniq 

Nếu họ không phải là một trên mỗi dòng, và bạn không nhớ chúng là một dòng trên mỗi dòng:

tr -s [:space:] \\n < filename | sort | uniq 

Điều đó không xóa dấu câu, vì vậy có thể bạn muốn :

tr -s [:space:][:punct:] \\n < filename | sort | uniq 

Nhưng điều đó sẽ xóa dấu gạch nối khỏi các từ được gạch nối. "man tr" để có thêm lựa chọn.

+0

mà làm việc cho tôi :) cảm ơn rất nhiều ... tôi chỉ cần đặt tất cả các từ trở lại trong một hàng với: cat testfile_out.txt | tr "\ n" "" "> testfile_out2.txt – cupakob

+10

" sắp xếp -u "sẽ loại bỏ nhu cầu uniq – Beano

1

Tôi nghĩ bạn sẽ muốn thay thế các dấu cách bằng dòng mới, sử dụng lệnh uniq để tìm duy nhất dòng, sau đó thay thế các dòng mới bằng dấu cách.

+0

uniq chỉ so sánh các dòng liền kề để nó không hoạt động. – Beano

+0

nó sẽ khi kết hợp với loại – Jonik

3

ruby -pi.bak -e '$_.split(",").uniq.join(",")' filename?

Tôi sẽ thừa nhận hai loại trích dẫn là xấu xí.

+2

Ruby không phải là lệnh Linux! Tôi đoán bằng lệnh Linux, anh ấy có nghĩa là các chương trình GNU thông thường. – Danny

+0

@Danny, tôi đã thấy điều đó, và bạn có thể làm điều này với một số giả kim thuật quá mức/trầm cảm, nhưng thực sự tôi nghĩ đây là một công việc cho một ngôn ngữ kịch bản. –

+0

+1 vì điều này dường như không thể phủ nhận thanh lịch, và dễ tiếp cận hơn đối với người chết so với Perl một lớp lót của Igor Krivokon :) – Jonik

1

Tôi giả sử bạn muốn các từ là duy nhất trên một dòng, chứ không phải trong suốt tệp. Nếu đây là trường hợp, thì kịch bản Perl bên dưới sẽ thực hiện thủ thuật.

while (<DATA>) 
{ 
    chomp; 
    my %seen =(); 
    my @words = split(m!,\s*!); 
    @words = grep { $seen{$_} ? 0 : ($seen{$_} = 1) } @words; 
    print join(", ", @words), "\n"; 
} 

__DATA__ 
word1, word2, word3, word2, word4, word5, word3, word6, word7, word3 

Nếu bạn muốn độc đáo trên toàn bộ tập tin, bạn chỉ có thể di chuyển %seen băm ngoài while(){} vòng lặp.

+2

Perl không phải là một lệnh Linux! Tôi đoán bằng lệnh Linux, anh ấy có nghĩa là các chương trình GNU thông thường. Sau đó, một lần nữa Perl được cài đặt ở khắp mọi nơi ... heh. – Danny

+0

Bạn có thể vui lòng chỉ ra định nghĩa của bạn về "lệnh Linux" là (hay đúng hơn là @ rbright's khi bạn có vẻ biết anh ta)? Có lẽ một lệnh được tìm thấy trong bản phân phối Linux? – Beano

+0

i có nghĩa là một lệnh, được tích hợp trong cài đặt mặc định của các distro phổ biến nhất ... ví dụ như somethink như grep. – cupakob

2

Tạo một danh sách duy nhất là nhờ khá dễ dàng để uniq, mặc dù hầu hết Unix lệnh như một mục nhập trên mỗi dòng thay vì một danh sách bằng dấu phẩy, vì vậy chúng ta phải bắt đầu bằng cách chuyển đổi nó để rằng:

$ sed 's/, /\n/g' filename | sort | uniq 
word1 
word2 
word3 
word4 
word5 
word6 
word7 

Phần khó khăn hơn là đặt điều này trên một dòng một lần nữa bằng dấu phẩy như dấu phân cách và không phải là các terminator. Tôi đã sử dụng perl một lớp lót để làm điều này, nhưng nếu ai đó có một cái gì đó thành ngữ hơn, xin vui lòng chỉnh sửa tôi. :)

$ sed 's/, /\n/g' filename | sort | uniq | perl -e '@a = <>; chomp @a; print((join ", ", @a), "\n")' 
word1, word2, word3, word4, word5, word6, word7 
+0

tr "" "\ n" có thể hiệu quả hơn sed trong trường hợp này là – florin

+0

và cũng đang hoạt động – cupakob

+0

Đặt trên một dòng khá đơn giản: sed 's /,/\ n/g' tên tệp | sắp xếp | dán -s -d, | sed 's /, /,/g' lệnh được dán, một lệnh rất đẹp! – Mapio

0

Và đừng quên lựa chọn -c hảo cho tiện ích uniq nếu bạn quan tâm đến việc một số các từ là tốt.

2

Dưới đây là một kịch bản awk mà sẽ để lại mỗi dòng trong sự khéo léo, chỉ loại bỏ những từ trùng lặp:

BEGIN { 
    FS=", " 
} 
{ 
    for (i=1; i <= NF; i++) 
     used[$i] = 1 
    for (x in used) 
     printf "%s, ",x 
    printf "\n" 
    split("", used) 
} 
+0

mà cũng hoạt động, nhưng không hoàn hảo;) đầu ra có chứa một từ với hai dấu phẩy .... rằng ist không phải là một vấn đề lớn :) cảm ơn rất nhiều – cupakob

1

Came qua thread này trong khi cố gắng để giải quyết nhiều vấn đề tương tự.Tôi đã ghép nối một số tệp chứa mật khẩu, vì vậy tự nhiên có rất nhiều gấp đôi. Ngoài ra, nhiều ký tự không chuẩn. Tôi không thực sự cần chúng được sắp xếp, nhưng nó có vẻ là cần thiết cho uniq.

tôi đã cố gắng:

sort /Users/me/Documents/file.txt | uniq -u 
sort: string comparison failed: Illegal byte sequence 
sort: Set LC_ALL='C' to work around the problem. 
sort: The strings compared were `t\203tonnement' and `t\203tonner' 

Cố gắng:

sort -u /Users/me/Documents/file.txt >> /Users/me/Documents/file2.txt 
sort: string comparison failed: Illegal byte sequence 
sort: Set LC_ALL='C' to work around the problem. 
sort: The strings compared were `t\203tonnement' and `t\203tonner'. 

Và thậm chí đã cố gắng đi qua nó thông qua con mèo đầu tiên, chỉ để tôi có thể nhìn thấy nếu chúng tôi đã nhận được một đầu vào thích hợp.

cat /Users/me/Documents/file.txt | sort | uniq -u > /Users/me/Documents/file2.txt 
sort: string comparison failed: Illegal byte sequence 
sort: Set LC_ALL='C' to work around the problem. 
sort: The strings compared were `zon\351s' and `zoologie'. 

Tôi không chắc điều gì đang xảy ra. Không tìm thấy các chuỗi "t \ 203tonnement" và "t \ 203tonner" trong tệp, mặc dù tìm thấy "t/203" và "tonnement", nhưng trên các dòng riêng biệt, không liền kề. Tương tự với "zon \ 351s".

gì cuối cùng làm việc đối với tôi là:

awk '!x[$0]++' /Users/me/Documents/file.txt > /Users/me/Documents/file2.txt 

Nó lời này cũng bảo quản có khác biệt duy nhất là trường hợp, đó là những gì tôi muốn. Tôi không cần danh sách được sắp xếp, vì vậy nó đã được tốt mà nó đã không được.

1

tôi đã có cùng một vấn đề ngày hôm nay .. một danh sách từ với 238.000 từ nhưng khoảng 40, 000 trong số đó là bản sao. Tôi đã có chúng trong dòng cá nhân bằng cách làm

cat filename | tr " " "\n" | sort 

để loại bỏ các bản sao Tôi chỉ đơn giản là làm

cat filename | uniq > newfilename . 

Làm việc một cách hoàn hảo không có lỗi và bây giờ tập tin của tôi là giảm so với 1.45MB để 1.01MB

0

mở tập tin với vim (vim filename) và chạy lệnh sắp xếp với cờ duy nhất (:sort u).

Các vấn đề liên quan