计算同一行中某个模式出现的次数

计算同一行中某个模式出现的次数

我需要在 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该程序中相同的操作:awksub()

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$stringxxxabc$stringawk

答案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。

https://raku.org/

答案4

使用GNUsed

echo abcsdabcsdabc | sed 's/abc/abc\n/g' | wc -w

相关内容