Функция UNIX Grep

У меня есть файл со столбцами, разделенными табуляцией. Я хочу вычислить уникальные записи в столбце. Однако я хочу вычислить уникальность на основе только ввода в столбце и удалить все последующие маркеры в скобках.

Таблица выглядит так:

1 abc def xxx(sd) 5677
2 ddd hhh yyy(dd) 4321
3 fds ggf xxx(df) 5666

Теперь я хочу подсчитать уникальное количество вычислений xxx и yyy.

Таким образом, ожидаемый результат должен быть 2, а я получаю 3.

Код, который я использовал:

cut -f4 f.txt| sort| uniq -D |wc -l

person Ankur    schedule 28.02.2014    source источник
comment
Обратите внимание, что sort имеет параметр -k, который позволяет вам сортировать по указанной части ввода, устраняя необходимость cut ввода в первую очередь.   -  person DevSolar    schedule 28.02.2014
comment
Я не понимаю, как это дало бы 3. Когда я запускаю его, после исправления команды cut, он равен 0, потому что четвертый столбец уникален для всех строк.   -  person Fred Foo    schedule 28.02.2014
comment
Количество символов в столбце, на основе которого должны быть рассчитаны уникальные записи, может варьироваться. Поэтому я хочу вычислить все возможные записи, если они уникальны.   -  person Ankur    schedule 28.02.2014
comment
начальное число также является столбцом   -  person Ankur    schedule 28.02.2014


Ответы (3)


Стандартная техника отладки: пошаговая работа, проверка промежуточного вывода.

С cut -f4 вы берете четвертое поле, которое в данном случае:

xxx(sd)
yyy(dd)
xxx(df)

Это три отдельные записи, независимо от того, как вы их отсортируете.

Продолжая мой комментарий относительно опции -k для sort, это дает ожидаемую цифру «2». (Я не уверен, что вы делаете с параметром -D для uniq.)

sort -k4.1,4.3 -u f.txt | wc -l

-k4.1,4.3 означает «сортировать по символам с 1-го по 3-й в 4-м поле», -u означает «список только уникальных строк», в результате получается:

1   abc def xxx(sd) 5677
2   ddd hhh yyy(dd) 4321

Вторая xxx строка не отличается и не попадает в список.


ИЗМЕНИТЬ:

В качестве альтернативы вы можете извлечь нужную часть строки ввода с помощью sed и передать эту в sort -u | wc -l. Я до сих пор не полностью понял спецификации вашего ввода, поэтому я все еще предполагаю здесь:

sed "s/\(\S\+\s\+\)\{3\}\([^(]\+\).*/\2/" f.txt

Объяснил:

  • \S\+\s\+ - 1..n пробелов, за которыми следует 1..n пробелов ...
  • \(\S\+\s\+\)\{3\} - ... трижды повторяется ...
  • \([^(]\+\) - ... за которым следуют 1..n символов, отличных от _18 _...
  • .* - ... за которым следует что-нибудь ...
  • /\2/ - ... заменить на то, что соответствует второй группе (1..n символов, отличных от ().

Это дает:

xxx
yyy
xxx
person DevSolar    schedule 28.02.2014
comment
но я хочу, чтобы он говорил мне, что xxx и yyy были уникальными, а не делали условие скобки частью уникального. - person Ankur; 28.02.2014
comment
например: cut -f4 дал мне xxx (sd) yyy (dd) xxx (df) xx (gg) yyz (rd) ... Теперь я хочу узнать, сколько уникальных xxx, yyy, xx, yyz есть. Меня не интересуют скобки, и я просто хочу, сколько раз повторяются значения перед скобками. - person Ankur; 28.02.2014
comment
@Ankur: Извините, но у меня проблемы с пониманием вашего намерения. Насколько я могу судить, мой ответ выполняет в точности то, о чем вы просите. Добавлены некоторые пояснения, чтобы было понятнее. - person DevSolar; 28.02.2014
comment
@Ankur: Добавлена ​​альтернатива с использованием sed. Вы сможете адаптировать одно из двух решений к своим потребностям. - person DevSolar; 28.02.2014
comment
Ввод может состоять из 2 символов, за которыми следует скобка, или из 6 символов, за которыми следует скобка. Так что это может быть xx (ds) или zzzzzz (hh) - person Ankur; 28.02.2014
comment
@Ankur: Тогда вариант sed - это правильный выбор, потому что, AFAIK, вы не можете сделать ни cut, ни sort для разделения полей в обоих табуляторе и скобке, что было бы тем, что вам нужно, чтобы сделать свой формат Работа. Если вы можете утверждать, что скобка в четвертом столбце на самом деле является единственной первой в записи, вы можете сделать проще sed "s/.*\s\([^(]\+\).*/\2/" f.txt. - person DevSolar; 28.02.2014

Что бы это ни стоило, вы также можете попробовать это, что даст вам подсчитать, сколько раз что-то было повторено (xxx и yyy):

cat test.txt | awk {'print substr($4,0,4)'} | sort | uniq --count

А если вам нужно только количество разных, просто добавьте wc -l, вот так

cat test.txt | awk {'print substr($4,0,4)'} | sort | uniq --count | wc -l

Я не уверен, что это лучший способ сделать это, но он работает.

Дайте мне знать, что вы думаете.

person dkasipovic    schedule 28.02.2014
comment
@Ankur: Судя по вашему комментарию к моему ответу, этот awk подведет вас, как только перед скобкой окажется меньше или больше 3 символов. Вам нужно указать точно возможный ввод, затем придумайте правильное извлечение того, что вы хотите подсчитать. Метод проб и ошибок никуда не годится. - person DevSolar; 28.02.2014
comment
Обратите внимание, что cat file | awk '...' можно переписать в awk '...' file. - person fedorqui 'SO stop harming'; 28.02.2014

Вы можете проверить, сколько раз появляется каждый блок, с помощью:

$ awk -F"[ (]" '{a[$4]++} END {for (i in a) print i, a[i]}' file
xxx 2
yyy 1

Объяснение

  • -F"[ (]" устанавливает разделитель полей как пробел или (.
  • {a[$4]++} отслеживает, сколько раз появляется 4-е поле (на основе этих разделителей полей, то есть xxx, _6 _...).
  • END {for (i in a) print i, a[i]} распечатывает результаты.

Если вас просто беспокоит, какие разные значения вы можете использовать:

$ awk -F"[ (]" '{a[$4]} END {for (i in a) print i}' file
xxx
yyy

Объяснение

  • -F"[ (]" устанавливает разделитель полей как пробел или (.
  • {a[$4]} отслеживает, какое 4-е поле появляется (на основе этих разделителей полей, то есть xxx, _13 _...).
  • END {for (i in a) print i} печатает результаты без счетчика.
person fedorqui 'SO stop harming'    schedule 28.02.2014