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

У меня есть. CSV файл:

[email protected],2009-11-27 01:05:47.893000000,example.net,127.0.0.1
[email protected],2009-11-27 00:58:29.793000000,example.net,255.255.255.0
[email protected],2009-11-27 00:58:29.646465785,example.net,256.255.255.0
...

Мне нужно удалить повторяющиеся электронные письма (всю строку) из файла (т.е. одну строку, содержащую [email protected] в приведенном выше примере). Как использовать uniq только поле 1 (разделенное запятыми)? Согласно man, uniq не имеет параметров для столбцов.

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

Ответ 1

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

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

[email protected],2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

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

дает:

1 01:05:47.893000000 2009-11-27 [email protected]
2 00:58:29.793000000 2009-11-27 [email protected]
1

Ответ 5

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

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

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

здесь

tac приведет к изменению строки файла по строке

Ответ 6

Вот очень изящный способ.

Сначала отформатируйте содержимое таким образом, чтобы столбец, который нужно сравнить для уникальности, является фиксированной шириной. Один из способов сделать это - использовать 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", $0 }' \
| uniq -f 7 -w 15 \
| awk '{ uniq_col=8; gsub(/ */, "", $uniq_col); printf "%s\n", $0 }'

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

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

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

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

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

Ответ 7

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

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

grep -v ',col2,' file > file_minus_offending_lines

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

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

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

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

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

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

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

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

Ответ 8

Сначала отсортировав файл с помощью sort, вы можете применить uniq.

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

$ cat test.csv
[email protected],2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv
[email protected],2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
[email protected],2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv | uniq
[email protected],2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
[email protected],2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

Вы также можете сделать магию AWK:

$ awk -F, '{ lines[$1] = $0 } END { for (l in lines) print lines[l] }' test.csv
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected],2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
[email protected]omain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0