7

Можно ли сделать grep подсчет нескольких вхождений в файле в одной команде? Например:

$ cat > file
blah alfa
beta blah
blah blahgamma
gamma

Я могу сделать:

grep -c 'alfa' file 
1 
grep -c 'beta' file  
1
grep -c 'gamma' file  
2

Но разве это возможно так:

grep -c -e 'alfa' -e 'beta' -e 'gamma' -somemoreblackmagic file

и получить счет для каждого из них?

alfa 1
beta 1
gamma 2

7 ответов7

4

Вы можете получить то, что вам нужно, просто используя grep, sort и uniq.

grep -EIho 'alfa|beta|gamma' *|sort|uniq -c
3

Еще одно решение awk , с добавленной оболочкой сценария оболочки:

#!/bin/sh –
awk '
BEGIN { split("alfa beta gamma", keyword)
        for (i in keyword) count[keyword[i]]=0
}
/alfa/  { count["alfa"]++ }
/beta/  { count["beta"]++ }
/gamma/ { count["gamma"]++ }
END   {
        for (i in keyword) print keyword[i], count[keyword[i]]
}'

Если вы хотите иметь возможность выбирать ключевые слова для поиска во время выполнения (и предоставлять их в качестве аргументов, как в ответе спарки), этот сценарий можно адаптировать для динамического создания сценария awk .

3

Я не думаю, что grep способен на то, что вы хотите сделать.

Просто используйте вместо этого awk :-)

Это решение может не работать для больших файлов (не оптимизировано). И работает только для простых слов, а не для регулярных выражений. Но при желании легко добавить некоторые функции.

Младшая версия с ограничениями, изложенными в комментариях ниже:

awk '
{
    split($0, b); for (i in b) ++A[b[i]]
}
END {
    split("'"$*"'", a)
    for (i in a) print sprintf("%s %d", a[i], A[a[i]])
}
'

просто передайте строки поиска непосредственно в скрипт

[РЕДАКТИРОВАТЬ]
исправлена версия с поддержкой регулярных выражений (см. комментарий ниже). Пожалуйста, скажите мне, если еще есть какие-либо открытые вопросы.

# ---- my favorite ----
awk -F' ?-c ' '
BEGIN { split("'"$*"'", a) }
{ for (i = 2; a[i]; ++i) if (match($0, a[i])) ++A[i] }
END { for (i = 2; a[i]; ++i) if (A[i]) print a[i] " " A[i] }
'
# ---- my favorite ----

пример использования:

script_name -c alfa -c beta -c gamma << !
alfa
beta
gamma
gamma
!

дает:

alfa 1
beta 1
gamma 2

использование регулярных выражений:

script_name -c   "^al"    -c "beta" -c gamma -c "m.$" << !
alfa
beta
gamma
gamma
!

дает:

^al 1
beta 1
gamma 2
m.$ 2

[/РЕДАКТИРОВАТЬ]

0

Я бы предложил использовать uniqsort).

$ sort file | uniq -c
1 alfa
1 beta
2 gamma

Вам нужна sort если файл не может быть отсортирован (на самом деле, только если множественные вхождения могут быть не в последовательных строках).

ОБНОВИТЬ:

Предполагая, что у вас есть предопределенные шаблоны, и они не содержат места:

$ PATTERNS='alfa beta gamma'

$ for P in $PATTERNS; do echo $P `grep -c $P file`; done
alfa 1
beta 1
gamma 2
0

Вот один пример из моей повседневной работы:

Все файлы, заканчивающиеся FlowBase.java, Количество вхождений строки «Input *»> 1

Пример: файл будет указан

"InputABD"

"InputABD"

$ для меня в $(найти. | grep FlowBase.java); do echo $ i $(egrep "input. " $ i | sed 's/^. "input//' | sed 's/";.*//' | uniq -c | awk '($ 1> 1) { print $ 2} '| wc -l); сделано | awk '($ 2> 0) {print $ 1}'

0

Perl решение:

perl -lne 'chomp;$s{$_}++ if /alpha|beta|gamma/ }{ print "$_ $s{$_}" for keys %s' file
0

Никакой grep не может сделать это за один проход, я бы предложил использовать awk:

awk -v pat='alfa beta gamma' '
  BEGIN { split(pat, p) } 

  { for(k in p) if($0 ~ p[k]) c[k]++ }

  END { for(k in p) print p[k], c[k]?c[k]:0 }
'

Или как довольно длинный однострочный

awk -v pat='alfa beta gamma' 'BEGIN { split(pat, p) } { for(k in p) if($0 ~ p[k]) c[k]++ } END { for(k in p) print p[k], c[k]?c[k]:0 }'

объяснение

pat разбивается на массив p , который затем используется для поиска совпадений в каждой строке ($0 ~ p[k]). Счетчики хранятся в массиве c . c[k]?c[k]:0 использует троичный оператор для вывода 0, когда c[k] равен нулю.

Обратите внимание, что если ваш шаблон содержит пробел, вам нужно использовать другой разделитель между шаблонами в pat и соответствующим образом обновить команду split .

тестирование

Входные данные:

cat << EOF > file
alfa
beta
gamma
gamma
EOF

Вывод с pat='alfa beta gamma':

alfa 1
beta 1
gamma 2

Входные данные:

cat << EOF > file
alfa beta
beta
gamma gamma
gamma alfa
alfalfa
alfa alfa
EOF

Вывод с pat='^a a$ alfa beta gamma':

beta 2                                          
gamma 2
^a 3
a$ 6
alfa 4

Выходные данные в обоих случаях совпадают с выходными данными запуска grep -c каждого шаблона в отдельности.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .