我需要在 shell 脚本中解决这个问题。我正在计算下面字符串出现的次数abc
,我想得到的答案是 3。
echo abcsdabcsdabc | grep -o abc
abc
abc
abc
假设我们没有-o
中的选项grep
,那么我们该如何处理呢?
答案1
将字符串视为由由 分隔的字段组成abc
:
$ echo abcsdabcsdabc | awk -F 'abc' '{ print (length > 0 ? NF - 1 : 0) }'
3
分隔符出现的次数abc
是 1 减去它分隔的字段数。
$ echo abcsdabcsdabc | awk '{ n=0; while (sub("abc", "xxx")) n++; print n }'
3
abc
这将替换该行中的子字符串xxx
并计算完成的次数,然后输出该数字。n=0
如果只有一行输入,则不需要。
gsub()
中的函数返回awk
进行替换的次数,因此上面的内容可以简化为
$ echo abcsdabcsdabc | awk '{ print gsub("abc", "xxx") }'
3
在 中,您可以执行与使用bash
该程序中相同的操作:awk
sub()
string=abcsdabcsdabc
n=0
while [[ $string == *abc* ]]; do
n=$(( n+1 ))
string=${string/abc/xxx} # replace first occurrence of "abc" with "xxx"
done
printf '%d\n' "$n"
这使用循环来替换中 的值中的while
子字符串,直到在 中找不到进一步出现的,就像上面的第二个程序一样。abc
$string
xxx
abc
$string
awk
答案2
和awk
:
awk -- 'BEGIN{print gsub(ARGV[2], "&", ARGV[1])}' abcsdabcsdabc abc
请注意,模式(此处abc
)被视为awk
扩展正则表达式(类似于grep -E
/支持的正则表达式egrep
)。
该语法允许主题和正则表达式包含多行。我们也避免echo
与无法输出任意数据相关的常见问题。
使用perl
正则表达式(类似于 GNUgrep -P
的):
perl -le 'print scalar (() = $ARGV[0] =~ m{$ARGV[1]}g)' -- abcsdabcsdabc abc
(但请注意,根据区域设置的编码,参数不会解释为文本。例如,在 UTF-8 区域设置中,使用 é
和.
作为参数,它将报告 2(字节)而不是 1(字符))。
使用zsh
,您可以执行以下操作:
occurrences() {
set -o localoptions -o extendedglob
local n=0
: ${1//(#m)$2/$((++n))}
echo $n
}
occurrences abcsdabcsdabc abc
这里,第二个参数 ( abc
) 被解释为固定字符串;替换$2
为$~2
,将其解释为扩展的 zsh glob 模式(具有比扩展正则表达式更广泛的功能集,但语法不同)。
答案3
使用 Raku(以前称为 Perl_6)
~$ echo "abcsdabcsdabc" | raku -ne '.match("abc", :global).say;'
(「abc」 「abc」 「abc」)
上面给出了匹配项(逐行)。下面给出了匹配的数量(逐行):
~$ echo "abcsdabcsdabc" | raku -ne '.match("abc", :global).elems.say;'
3
注意::global
参数可以缩写为:g
。
HTH。
答案4
使用GNUsed
echo abcsdabcsdabc | sed 's/abc/abc\n/g' | wc -w