Чи є спосіб видалити повторювані рядки з файлу в Unix?
Я можу зробити це з sort -uі uniqкоманд, але я хочу використовувати sedабо awk. Це можливо?
awk, але для великих файлів буде витрачено багато ресурсів.
Чи є спосіб видалити повторювані рядки з файлу в Unix?
Я можу зробити це з sort -uі uniqкоманд, але я хочу використовувати sedабо awk. Це можливо?
awk, але для великих файлів буде витрачено багато ресурсів.
Відповіді:
awk '!seen[$0]++' file.txt
seenце асоціативний масив, до якого Awk передасть кожен рядок файлу. Якщо рядок відсутній у масиві, то seen[$0]він оцінить значення false. Це !логічний оператор НЕ і перетворить помилкове в істинне. Awk надрукує рядки, в яких вираз оцінюється на істинне. У ++прирости seenтак , що seen[$0] == 1після того, як в перший раз рядок знайдена , а потім seen[$0] == 2, і так далі.
Awk оцінює все, окрім 0та ""(порожній рядок) до true. Якщо дублікат буде розміщений у, seenтоді він !seen[$0]буде оцінюватись як хибний, а рядок не буде записаний у висновок.
awk '!seen[$0]++' merge_all.txt > output.txt
for f in *.txt; do gawk -i inplace '!seen[$0]++' "$f"; done
З http://sed.sourceforge.net/sed1line.txt : (Будь ласка, не запитуйте мене, як це працює ;-))
# delete duplicate, consecutive lines from a file (emulates "uniq").
# First line in a set of duplicate lines is kept, rest are deleted.
sed '$!N; /^\(.*\)\n\1$/!P; D'
# delete duplicate, nonconsecutive lines from a file. Beware not to
# overflow the buffer size of the hold space, or else use GNU sed.
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
$!потрібна частина? Не sed 'N; /^\(.*\)\n\1$/!P; D'робить те саме? Я не можу придумати приклад, коли на моїй машині два різні (fwiw, я намагався в кінці порожнього рядка з обома версіями, і вони обидва чудово).
[ -~]представляє діапазон символів ASCII від 0x20 (пробіл) до 0x7E (тильда). Вони розглядаються в друкуються символи ASCII (пов'язана сторінка також 0x7F / видалення , але це не здається правильним). Це робить рішення порушеним для тих, хто не використовує ASCII, або хтось, хто використовує, скажімо, символи вкладки .. Більш портативний [^\n]включає насправді набагато більше символів ... насправді всі вони, крім одного.
Perl one-liner схожий на awk рішення @ jonas:
perl -ne 'print if ! $x{$_}++' file
Ця варіація видаляє пробіл пробілу перед порівнянням:
perl -lne 's/\s*$//; print if ! $x{$_}++' file
Ця варіація редагує файл на місці:
perl -i -ne 'print if ! $x{$_}++' file
Цей варіант редагує файл на місці та робить резервну копію file.bak
perl -i.bak -ne 'print if ! $x{$_}++' file
Однокласинка, яку розмістив Андре Міллер вище, працює за винятком останніх версій sed, коли вхідний файл закінчується порожнім рядком і не має символів. На моєму Mac мій процесор просто обертається.
Нескінченний цикл, якщо останній рядок порожній і не має символів :
sed '$!N; /^\(.*\)\n\1$/!P; D'
Не висить, але ви втрачаєте останній рядок
sed '$d;N; /^\(.*\)\n\1$/!P; D'
Пояснення знаходиться в самому кінці седу FAQ :
Підтримувач GNU sed вважав, що, незважаючи на проблеми з портативністю,
це може спричинити, зміна команди N для друку (а не
видалення) простір шаблону більше відповідає інтуїції
про те, як повинна вести себе команда "додавати наступний рядок" .
Ще один факт, що сприяє зміні, полягав у тому, що "{N; команда;}"
видалить останній рядок, якщо файл має непарне число рядків, але
надрукує останній рядок, якщо файл має парну кількість рядків.Для перетворення сценаріїв, які використовували колишню поведінку N (видалення
простору шаблону при досягненні EOF), до скриптів, сумісних з
усіма версіями sed, змінити одинокий "N;" до "$ d; N;" .
$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr '$!N;/^(.*)\n\1$/!P;D'
1
2
3
4
5
основна ідея:
print ONLY once of each duplicate consecutive lines at its LAST appearance and use D command to implement LOOP.
Пояснює:
$!N;: якщо поточний рядок НЕ останній рядок, використовуйте Nкоманду для читання наступного рядка в pattern space./^(.*)\n\1$/!P: якщо вміст струму розділено pattern spaceдвома , що означає, що наступний рядок є поточним рядком, ми НЕ можемо роздрукувати його відповідно до нашої основної ідеї; в іншому випадку, що означає, що поточний рядок є ОСТАННІМ появою всіх його повторюваних послідовних рядків, тепер ми можемо використовувати команду для друку символів у поточній утиліті ( також надрукованій).duplicate string\nsamePpattern space\n\nD: ми використовуємо Dкоманду для видалення символів у поточній pattern spaceутиліті \n( \nтакож видаленій), тоді вміст pattern spaceнаступного рядка.Dкоманда змусить sedперейти до своєї FIRSTкоманди $!N, але НЕ читати наступний рядок з файлу або стандартного потоку введення.$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr 'p;:loop;$!N;s/^(.*)\n\1$/\1/;tloop;D'
1
2
3
4
5
основна ідея:
print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP.
Пояснює:
:loopкоманду set labelназви loop.Nдля читання наступного рядка в pattern space.s/^(.*)\n\1$/\1/для видалення поточного рядка, якщо наступний рядок збігається з поточним рядком, ми використовуємо sкоманду для виконання deleteдії.sкоманда виконана успішно, то використовуйте tloopкомандну силу, sedщоб перейти до labelназваного loop, що зробить той самий цикл до наступних рядків утиліту, немає жодних повторюваних послідовних рядків рядка, який є latest printed; в іншому випадку використовуйте Dкоманду до deleteрядка, який збігається з latest-printed line, і примушуйте sedперейти до першої команди, яка є pкомандою, зміст поточного pattern space- наступний новий рядок.busybox echo -e "1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5" | busybox sed -nr "$!N;/^(.*)\n\1$/!P;D"
cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'
Видаляє повторювані рядки за допомогою awk.
uniqодного достатньо.