2009-06-04 1 views
17

У меня есть простой текстовый файл со словами, которые отделены друг от друга запятой, например:Как удалить повторяющиеся слова из текстового файла с помощью команды Линукс

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

я хочу, чтобы удалить дубликаты и стать :

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

Любые идеи? Я думаю, egrep может мне помочь, но я не уверен, как использовать его точно ....

+1

Вы хотите, чтобы слова были уникальными на основе строк или над всем файлом? Также вы хотите сохранить исходный порядок слов, или вы счастливы, если заказ изменен? – Beano

+0

Мне нужны слова uniq во всем файле. порядок слов не важен. – cupakob

+0

См. Также: [Как найти повторяющиеся слова в файле с помощью grep/egrep?] (Http://stackoverflow.com/q/33396629/562769) –

ответ

28

Предполагая, что слова по одному в строке, а файл уже отсортирован:

uniq filename 

Если файл не отсортирован:

sort filename | uniq 

Если они не один на линии, и вы не возражаете против того, чтобы они были по одному в строке:

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

Это не устраняет пунктуацию, хотя, возможно, вы хотите :

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

Но это снимает дефис с дефиса. «man tr» для большего количества опций.

+0

, которая работает для меня :) Большое спасибо ... Мне нужно всего лишь вернуть все слова в одну строку: cat testfile_out.txt | tr "\ n" ""> testfile_out2.txt – cupakob

+10

"sort -u" удалит необходимость uniq – Beano

1

Я думаю, вы захотите заменить пространства символами новой строки, используйте команду uniq, чтобы найти уникальную линий, затем снова замените строки новой строки пробелами.

+0

uniq сравнивает только смежные строки, поэтому это не сработает. – Beano

+0

это будет в сочетании с сортировкой – Jonik

3

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

Я признаю, что два вида цитат являются уродливыми.

+2

Ruby не является командой Linux! Я предполагаю, что команда Linux означает регулярные программы GNU. – Danny

+0

@ Danny, я видел это, и вы могли бы сделать это с некоторой чрезмерной alchemy sed/awk, но на самом деле я думаю, что это работа для языка сценариев. –

+0

+1, как это кажется неоспоримо элегантным и более доступным для смертных по сравнению с Perl однострочника Игоря Krivokon в :) – Jonik

1

Предполагалось, что вы хотите, чтобы слова были уникальными на одной строке, а не на всем протяжении файла. Если это так, то скрипт Perl ниже выполнит трюк.

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 

Если вы хотите уникальность через весь файл, вы можете просто переместить %seen хэш вне цикла while(){}.

+2

Perl не является командой Linux! Я предполагаю, что команда Linux означает регулярные программы GNU. Затем снова Perl устанавливается везде ... хе. – Danny

+0

Не могли бы вы указать, что означает ваше определение «команды Linux» (или, скорее, @ rbright, как вы, кажется, знаете его)? Может быть, команда найдена в дистрибутивах Linux? – Beano

+0

Я имею в виду команду, которая интегрирована в установку по умолчанию самых популярных дистрибутивов ... например, sometink like grep. – cupakob

2

Создание уникального списка довольно легко благодаря uniq, хотя большинство Unix команд как одна запись в строке вместо списка разделенных запятыми, поэтому мы должны начать с преобразования его в том, что:

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

Более сложная часть снова помещает это на одну строку запятыми как разделители, а не терминаторы. Я использовал perl one-liner для этого, но если у кого-то есть что-то более идиоматическое, пожалуйста, отредактируйте меня. :)

$ 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" может быть более эффективным, чем sed в этом случае – florin

+0

, и это также работает – cupakob

+0

Положить это на одну строку довольно просто: sed 's /,/\ n/g' filename | сортировать | paste -s -d, | sed 's /, /,/g' Команда - паста, очень хорошая! – Mapio

0

И не забывайте -c опции утилиты uniq, если вы заинтересованы в получении количества слов, а также.

2

Вот сценарий AWK, который оставит каждую строку в такт, только удалив повторяющиеся слова:

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

, который также работает, но не идеален;) вывод содержит слово с двумя запятыми .... это не большая проблема :) Большое спасибо – cupakob

1

Сталкивался эту тему, пытаясь решить много с той же проблемой.Я объединил несколько файлов, содержащих пароли, поэтому, естественно, было много парных. Кроме того, многие нестандартные символы. Мне они действительно не нужны, но, похоже, это было необходимо для uniq.

Я пробовал:

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' 

Пробовал:

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'. 

И даже пытался передать его через кошку первой, только чтобы я мог видеть, если мы получали надлежащего ввода.

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 \ 203tonnement» и «t \ 203tonner» не найдены в файле, хотя найдены «t/203» и «tonnement», но на отдельных соседних строках. То же самое с «zon \ 351s».

Что, наконец, работал для меня было:

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

Она также сохранились слова, единственным отличием было так, что я и хотел. Мне не нужен список, отсортированный, так что было здорово, что это не так.

1

У меня была такая же проблема сегодня .. список слов с 238 000 слов, но около 40 000 из них были дубликатами. Я уже имел их в отдельных линиях, делая

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

удалить дубликаты, я просто сделал

cat filename | uniq > newfilename . 

Работал отлично без ошибок и теперь мой файл вниз от 1.45MB до 1.01MB

0

открыть файл с помощью vim (vim filename) и запустить команду сортировки с уникальным флагом (:sort u).

Смежные вопросы