Есть ли способ "uniq" по столбцу?

у меня есть .csv файл, как это:

stack2@example.com,2009-11-27 01:05:47.893000000,example.net,127.0.0.1
overflow@example.com,2009-11-27 00:58:29.793000000,example.net,255.255.255.0
overflow@example.com,2009-11-27 00:58:29.646465785,example.net,256.255.255.0
...

Я должен удалить дубликаты электронных писем (всю строку) из файла (т. е. одну из строк, содержащих overflow@example.com в приведенном выше примере). Как использовать uniq только в поле 1 (разделено запятыми)? Согласно man, uniq не имеет параметров для столбцов.

Я пробовал что-то с sort | uniq но это не работает.

8 ответов


sort -u -t, -k1,1 file
  • -u уникальный
  • -t, так запятая является разделителем
  • -k1,1 для ключевого поля 1

результат теста:

overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 

awk -F"," '!_[]++' file
  • -F задает разделитель полей.
  • это первое поле.
  • _[val] ищет val в хэш -_(регулярная переменная).
  • ++ increment и возвращает старое значение.
  • ! возвращает логическое не.
  • в конце есть неявная печать.

рассмотреть несколько столбцов.

сортировать и давать уникальный список на основе столбца 1 и столбца 3:

sort -u -t : -k 1,1 -k 3,3 test.txt
  • -t : двоеточие-это разделитель
  • -k 1,1 -k 3,3 на основе столбца 1 и столбца 3

или если вы хотите использовать uniq:

<mycvs.cvs tr -s ',' ' ' | awk '{print " "" "}' | uniq -c -f2

выдает:

1 01:05:47.893000000 2009-11-27 tack2@domain.com
2 00:58:29.793000000 2009-11-27 overflow@domain2.com
1

Если вы хотите сохранить последний из дубликатов, которые вы можете использовать

 tac a.csv | sort -u -t, -r -k1,1 |tac

что было моим требованием

здесь

tac перевернет файл строка за строкой


вот очень интересный способ.

сначала отформатируйте содержимое так, чтобы столбец для сравнения уникальности был фиксированной шириной. Один из способов сделать это-использовать awk printf с описателем ширины поля/столбца ("%15s").

Теперь опции-f и-w uniq можно использовать для пропуска предыдущих полей / столбцов и указания ширины сравнения (ширина столбцов).

вот три примера.

В первом примере...

1) Временно сделайте интересующий столбец фиксированной шириной, большей или равной максимальной ширине поля.

2) используйте опцию-F uniq, чтобы пропустить предыдущие столбцы, и используйте опцию-w uniq, чтобы ограничить ширину tmp_fixed_width.

3) Удалите конечные пробелы из столбца, чтобы" восстановить " его ширину (при условии, что раньше не было конечных пробелов).

printf "%s" "$str" \
| awk '{ tmp_fixed_width=15; uniq_col=8; w=tmp_fixed_width-length($uniq_col); for (i=0;i<w;i++) { $uniq_col=$uniq_col" "}; printf "%s\n",  }' \
| uniq -f 7 -w 15 \
| awk '{ uniq_col=8; gsub(/ */, "", $uniq_col); printf "%s\n",  }'

во втором примере...

создайте новый столбец uniq 1. Затем удалите его после применен фильтр uniq.

printf "%s" "$str" \
| awk '{ uniq_col_1=4; printf "%15s %s\n", uniq_col_1,  }' \
| uniq -f 0 -w 15 \
| awk '{ =""; gsub(/^ */, "", ); printf "%s\n",  }'

третий пример такой же, как и второй, но для нескольких столбцов.

printf "%s" "$str" \
| awk '{ uniq_col_1=4; uniq_col_2=8; printf "%5s %15s %s\n", uniq_col_1, uniq_col_2,  }' \
| uniq -f 0 -w 5 \
| uniq -f 1 -w 15 \
| awk '{ ==""; gsub(/^ */, "", ); printf "%s\n",  }'

ну, проще, чем изолировать столбец с помощью awk, если вам нужно удалить все с определенным значением для данного файла, почему бы просто не сделать grep-v:

например, удалить все со значением "col2" во-вторых строка: столбец col1,и col2,с col3,col4

grep -v ',col2,' file > file_minus_offending_lines

если этого недостаточно, потому что некоторые строки могут быть неправильно удалены, возможно, соответствующее значение отображается в другом столбце, вы можете сделать что-то вроде этого:

awk, чтобы выделить столбец обидеть : например,

awk -F, '{print  "|" $line}'

- F задает поле с разделителями",", $2 означает столбец 2, за которым следует некоторый пользовательский разделитель, а затем вся строка. Затем вы можете фильтровать, удаляя строки, которые начать С оскорбительным значением:

 awk -F, '{print  "|" $line}' | grep -v ^BAD_VALUE

а затем удалите материал перед разделителем:

awk -F, '{print  "|" $line}' | grep -v ^BAD_VALUE | sed 's/.*|//g'

(Примечание-команда sed небрежна, потому что она не включает экранирование значений. Также шаблон sed действительно должен быть что-то вроде "[^|]+" (т. е. ничего не разделитель). Но, надеюсь, это достаточно ясно.


сортируя файл с помощью sort во-первых, вы можете подать заявку uniq.

кажется, что сортировать файл просто отлично:

$ cat test.csv
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv | uniq
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

вы также можете сделать некоторые AWK магии:

$ awk -F, '{ lines[] =  } END { for (l in lines) print lines[l] }' test.csv
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0