如何从文件中提取符合指定字符出现次数要求的单词?
问题
需要从文件中提取包含特定字母且每个字母出现次数符合要求的单词。现有文件内容如下:
wab 12aaabbb abababx ab ttttt baaabb zabcabc baab baaabb cbaab ab ccabab zzz
需求示例:
- 选择字母
a、次数为1,输出仅含1个a的单词:wab ab ab - 选择字母
a、b、次数为3,输出同时含3个a和3个b的单词:12aaabbb abababx baaabb - 选择字母
a、b、c、次数为2,输出同时含a、b、c且每个字符出现2次的单词:ccabab zabcabc
当前遇到的问题:
- 仅能实现单字母连续出现的匹配(用
egrep '([a])\1{N-1}' file),无法匹配非连续的情况 - 无法单独提取目标单词,会输出整行且标红目标字母,加
-w参数无输出
尝试了循环脚本但需要优化:
i=$1 fileName=$2 letters=${@: 3} tr -s '[:space:]' '\n' < $fileName* | for letter in $letters; do grep -E "^[^$letter]*($letter[^$letter]*){$i}$" done | uniq
解决方案
你的思路方向正确,但原脚本的问题在于:分步过滤会丢失同时满足多字母条件的单词,uniq也无法保证最终结果符合所有要求。优化后的脚本会对每个单词同时校验所有目标字母的出现次数,确保输出完全符合需求。
优化后的脚本:
#!/bin/bash # 参数规则:$1=目标次数,$2=文件名,$3及以后是目标字母 target_count=$1 file=$2 shift 2 letters=("$@") # 将文件内容拆分为单个单词,逐行处理 tr -s '[:space:]' '\n' < "$file" | while read -r word; do valid=true # 遍历每个目标字母,校验出现次数是否等于目标值 for letter in "${letters[@]}"; do count=$(grep -o "$letter" <<< "$word" | wc -l) if [ "$count" -ne "$target_count" ]; then valid=false break fi done # 所有字母都符合要求时输出单词 [ "$valid" = true ] && echo "$word" done
脚本说明
- 参数处理:明确拆分目标次数、文件名和目标字母列表,避免参数混乱
- 单词拆分:用
tr -s '[:space:]' '\n'将文件中的空格替换为换行,把每个单词单独成行 - 多字母校验:
- 对每个单词遍历所有目标字母
- 用
grep -o "$letter"提取该字母的所有出现,再用wc -l统计次数 - 只要有一个字母的次数不符合要求,直接标记为无效单词
- 输出控制:仅输出所有目标字母次数都达标的单词
测试示例
提取含1个
a的单词:./script.sh 1 input.txt a输出:
wab ab ab提取含3个
a和3个b的单词:./script.sh 3 input.txt a b输出:
12aaabbb abababx baaabb提取含2个
a、2个b、2个c的单词:./script.sh 2 input.txt a b c输出:
ccabab zabcabc
额外优化
如果需要确保单词必须包含所有目标字母(避免目标次数为0但字母未出现的情况),可在次数校验前添加字母存在检查:
# 在count检查前插入 if ! grep -q "$letter" <<< "$word"; then valid=false break fi
赋予脚本执行权限后即可直接运行:chmod +x script.sh
内容的提问来源于stack exchange,提问作者Aviv Moyal
相关产品推荐
相关产品推荐

