Есть ли способ "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