Удалить дубликаты csv на основе первого значения, сохраняя самую длинную строку между дубликатами

В большинстве случаев виноват брандмауэр. Выполните service iptables stopи service ip6tables stop.

Если остановка службы не работает, выполните сброс iptable.

iptables --flush.

Если это виртуальная машина, сделайте то же самое и на хосте

1
02.04.2020, 14:52
2 ответа

Я предполагаю, что ваши поля определены ;. И что не может быть ;внутри поля. Если эти предположения верны, вы можете сделать:

$ awk -F';' '{if(!a[$1]||length($0)>length(a[$1])){a[$1]=$0}}END{for(i in a){print a[i]}}' file.txt
Aerial Assault (USA);Aerial Assault (USA);Sega Master System;;1990;Sega;Shooter;;;;;0;;;;;
After Burner (World);After Burner (World);Sega Master System;;1988;Sega;Flying;;;;;0;;;;;
Aladdin (Europe);Aladdin (Europe);Sega Master System;;1994;Sega;Platform;;;;;0;;;;;
Air Rescue (Europe);Air Rescue (Europe);Sega Master System;;1992;Sega;Shooter;;;;;0;;;;;

Однако у этого есть недостаток, заключающийся в необходимости хранить в памяти одну строку на 1-е поле, и это может быть проблемой для больших файлов. Если это так, вы можете попробовать это:

$ awk '{print length($0)";"$0}' file.txt | sort -t';' -rnk1,1 | awk -F';' '++a[$2]==1' | cut -d';' -f2-
Aerial Assault (USA);Aerial Assault (USA);Sega Master System;;;;;;;;;0;;;;;
After Burner (World);After Burner (World);Sega Master System;;;;;;;;;;;;;;
Air Rescue (Europe);Air Rescue (Europe);Sega Master System;;1992;Sega;Shooter;;;;;0;;;;;
Aladdin (Europe);Aladdin (Europe);Sega Master System;;1994;Sega;Platform;;;;;0;;;;;

Вы можете применить любое решение ко всем вашим файлам с помощью простого цикла оболочки:

for f in *txt; do 
    awk -F';' '{if(!a[$1]||length($0)>length(a[$1])){a[$1]=$0}}END{for(i in a){print a[i]}}' "$f" > "$f".fixed
done

Или

for f in *txt; do 
    awk '{print length($0)";"$0}' file.txt | sort -t';' -rnk1,1 | 
        awk -F';' '++a[$2]==1' | cut -d';' -f2- > "$f".fixed
done
1
28.04.2021, 23:19

Попробуйтеsort(1):

sort -rt';' filename | sort -t';' -usk1,1

Aerial Assault (USA);Aerial Assault (USA);Sega Master System;;1990;Sega;Shooter;;;;;0;;;;;
After Burner (World);After Burner (World);Sega Master System;;1988;Sega;Flying;;;;;0;;;;;
Air Rescue (Europe);Air Rescue (Europe);Sega Master System;;1992;Sega;Shooter;;;;;0;;;;;
Aladdin (Europe);Aladdin (Europe);Sega Master System;;1994;Sega;Platform;;;;;0;;;;;

Оба вида будут использовать ;в качестве разделителя полей(-t';'). Первая сортирует в обратном порядке (-r), так что пустые поля идут после непустых -полей, а вторая сортирует по первому полю(-k1,1)и удаляет лишние строки с то же самое первое поле(-u= uniq ), но в остальном будет поддерживаться порядок, установленный первой сортировкой(-s= стабильный ).

Это предполагает, что вместо «самой длинной» строки, как говорится в заголовке, вам действительно нужна «самая полная», т.е. между двумя строками с одним и тем же первым полем более короткая всегда имеет подмножество полей более длинной (, что является единственным случаем, когда отбрасывание более коротких строк может иметь какой-либо смысл ИМХО ). Также предполагается, что ваша реализация сортировки имеет-s(стабильную )опцию :как в GNU (, Linux ), так и в сортировке BSD.

Если вы хотите сделать это с пакетом файлов, вы должны использоватьfind:

find dir -type f -name '*.txt' \
    -exec sh -c 'for f; do sort -rt";" "$f" |
    sort -t";" -usk1,1 > "$f.new" && echo mv "$f.new" "$f"; done' sh {} +

Настройте предикаты поиска(-nameи т. д. )и удалите echoиз предыдущего mv, только если вы готовы уничтожить существующие файлы.

0
28.04.2021, 23:19

Теги

Похожие вопросы