Bash中d=${c//[^$b]}如何统计$c内指定字符$b的出现次数?
相关Bash统计脚本
#!/bin/bash echo "The program checks the number of indicated letters" echo "Enter the file name and path" read a c=$(cat $a) echo " Enter which letter is to be found. for examle 'a' " read b d=${c//[^$b]} echo "The number of occurrences of the character is: " ${#d}
${c//[^$b]} 行逻辑拆解 你之前了解的[^...]匹配方括号范围外任意字符的规则是完全正确的,觉得逻辑矛盾,是因为没搞懂这行用的是Bash的参数扩展全局替换语法,走的是「反向删除非目标字符」的统计思路,不是正向匹配目标字符计数。
逐段拆解语法规则:
${var//match/replace}是Bash原生的全局字符串替换语法:会把变量var中所有符合match规则的内容,全部替换为replace位置的内容;如果replace位置留空,效果就是删除所有匹配到的内容。- 这行里的匹配规则是
[^$b]:当你输入待统计字符比如a时,变量$b会展开为a,匹配规则就变成[^a],即匹配所有不等于a的字符。 - 因为替换位置是空值,这行实际执行的操作是:把读入的文件内容变量
c里,所有不是你指定字符的内容全部删掉,最终变量d里剩下的字符,全是你要统计的目标字符。 - 末尾的
${#d}是Bash取变量字符串长度的语法,剩下的字符串全是目标字符,长度值自然就是该字符在文件中的总出现次数。
参考资料的误区说明
你查到的"[^d]"匹配b到d范围外字符的描述是错误的,混淆了方括号通配的两个不同规则:
- 只有方括号内出现
[起始字符-结束字符]这种横杠连接两个字符的写法时,才代表匹配指定的字符范围,比如[b-d]才是匹配b、c、d三个字符。 - 如果
^是方括号内的第一个字符,它的唯一作用是对匹配集合取反,和范围匹配没有任何关系:[^a]就是匹配所有不是a的字符,[^b-d]才是匹配所有不在b到d范围内的字符。
举个实际运行的例子方便理解:
- 假设目标文件内容是
abac123a,读入后c变量值就是这段文本 - 你输入待统计字符
a,此时$b展开为a,匹配规则为[^a] - 所有非a的字符
b/c/1/2/3会被全部删除,最终d变量值为aaa - 取
d的长度得到3,就是文件中字符a的出现次数,和脚本实际运行结果一致。
补充说明:这个脚本存在小缺陷,如果你输入的待查找内容是多个字符,统计结果会不符合预期——因为方括号通配里[^abc]代表匹配所有不是a/b/c的字符,删除后剩下的是所有a/b/c字符,统计的是这几个字符的总出现次数,不是单个字符的计数。
内容的提问来源于stack exchange,提问作者czitak
相关产品推荐
相关产品推荐

