Порахуйте події символів у рядку за допомогою Bash


123

Мені потрібно порахувати кількість вхідних знаків у рядку за допомогою 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
@Amir Що ти очікуєш?
hek2mgl

3
Ви можете пропустити wc -l, просто використовувати grep -c, він працює як на bsd grep, так і на Linux grep.
andsens

8
@andsens grep -cвиведе лише кількість відповідних рядків. Він не рахує декількох матчів на рядок.
hek2mgl

1
Я хочу порахувати '$' в рядку, як я можу уникнути '$' з головної рядки?
маст

117

Ви можете, наприклад, видалити всі інші символи і порахувати, що залишилося, як-от:

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? Це гольфи!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

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

Блок 4 коду - найкращий на мій погляд. Нам потрібно легше дістатися до:tr -dc ',' <<<"$var" | wc -c
bgStack15

68

Зробити це можна, комбінуючи trі wcкоманди. Наприклад, рахувати eв рядку referee

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

вихід

4

Пояснення: Команда tr -cd 'e'видаляє всі символи, окрім 'e', ​​а Command wc -cрахує залишки символів.

Кілька рядків введення також добре для цього рішення, як команда cat mytext.txt | tr -cd 'e' | wc -cможе рахувати eу файлі mytext.txt, навіть думаючи, що файл може містити багато рядків.


3
Ваше рішення, здається, найчистіше і найлегше запам'ятати, дякую!
Джиріслав

Це чудово. Дякую!
Kodie Grantham

Я люблю це, бо ненавиджу awk!
франциск

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.