Подсчет вхождений символа в строку с помощью Bash


124

Мне нужно подсчитать количество вхождений символа в строку с помощью Bash.

В следующем примере, когда полукокс (например) t, то echo˙s правильного числа вхождений tв var, но , когда символ запятая или точка с запятой, она выводит ноль:

var = "text,text,text,text" 
num = `expr match $var [,]`
echo "$num"

Ответы:


118

Я бы использовал следующую awkкоманду:

string="text,text,text,text"
char=","
awk -F"${char}" '{print NF-1}' <<< "${string}"

Я разделяю строку на $charи печатаю количество результирующих полей минус 1.

Если ваша оболочка не поддерживает <<<оператора, используйте echo:

echo "${string}" | awk -F"${char}" '{print NF-1}'

5
@HattrickNZ Тогда используйте:$(grep -o "$needle" < filename | wc -l)
hek2mgl

13
@ Амир Чего ты ждешь?
hek2mgl

3
Вы можете пропустить wc -l, просто используйте grep -c, он работает как с bsd grep, так и с linux grep.
andsens 05

8
@andsens grep -cвыведет только количество совпадающих строк. Он не учитывает несколько совпадений в строке.
hek2mgl 05

1
Я хочу посчитать символы $ в строке, как мне избежать символа $ из основной строки?
masT 06

118

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

var="text,text,text,text"
res="${var//[^,]}"
echo "$res"
echo "${#res}"

напечатает

,,,
3

или

tr -dc ',' <<<"$var" | awk '{ print length; }'

или

tr -dc ',' <<<"$var" | wc -c    #works, but i don't like wc.. ;)

или

awk -F, '{print NF-1}' <<<"$var"

или

grep -o ',' <<<"$var" | grep -c .

или

perl -nle 'print s/,//g' <<<"$var"

1
еще один трюк вродеy="${x//[^s|S]}"; echo "${#y}"
Водолей Сила

4
используйте первый, всегда следует избегать создания другого процесса для выполнения подобной работы, это может серьезно повлиять на производительность при использовании с большими циклами итераций. Как правило, выполнение внешнего процесса должно быть крайней мерой при использовании повторяющихся или повторяющихся операций.
osirisgothra

Почему тебе не нравится wc? Это гольф!
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 六四 事件 法轮功 包 卓 轩 потому что напримерecho -n some line | wc -l
jm666

На мой взгляд, блок кода 4 - лучший. Нам нужно упростить tr -dc ',' <<<"$var" | wc -c
доступ

69

Вы можете сделать это путем объединения trи wcкоманды. Например, чтобы посчитать eв строке referee

echo "referee" | tr -cd 'e' | wc -c

вывод

4

Пояснения: Команда tr -cd 'e'удаляет все символы, кроме 'e', ​​а Команда wc -cсчитает оставшиеся символы.

Несколько строк ввода также хороши для этого решения, как команда cat mytext.txt | tr -cd 'e' | wc -cтазов подсчеты eв файле mytext.txt, даже думали , что файл может содержать много строк.


3
Ваше решение кажется самым чистым и простым для запоминания, спасибо!
jirislav

Это круто. Спасибо!
Kodie Grantham

Мне это нравится, потому что я ненавижу awk!
franzisk

3

Это самая короткая и приятная версия, основанная на всех замечательных ответах и ​​комментариях:

grep -o "$needle" <<< "$haystack" | wc -l


2

awk работает хорошо, если он есть на вашем сервере

var="text,text,text,text" 
num=$(echo "${var}" | awk -F, '{print NF-1}')
echo "${num}"

В качестве примечания: awk -F,ищет файл ,. Вы можете сделать следующее:awk -F"${your_char}"
Emixam23,

1

Я бы предложил следующее:

var="any given string"
N=${#var}
G=${var//g/}
G=${#G}
(( G = N - G ))
echo "$G"

Никаких звонков в другие программы


1

также проверьте это, например, мы хотим посчитать t

echo "test" | awk -v RS='t' 'END{print NR-1}'

или в python

python -c 'print "this is for test".count("t")'

или даже лучше, мы можем сделать наш скрипт динамическим с помощью awk

echo 'test' | awk '{for (i=1 ; i<=NF ; i++) array[$i]++ } END{ for (char in array) print char,array[char]}' FS=""

в этом случае вывод будет таким:

e 1
s 1
t 2
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.