如何在Bash脚本中从现有字符串提取唯一字符的字符串?
Bash 字符串去重(提取唯一字符)
问题描述
现有字符串:
explicit_borders="\"\"''()"需要生成仅包含唯一字符的结果字符串:
distinct_border_chars="\"'()" # 仅保留唯一字符集合疑问:是否必须逐个遍历字符,仅当结果字符串中不存在该字符时才添加?有没有更简便的Bash专属解决方案?
更新要求:优先选择**基于Bash内置命令、不创建额外子shell(不使用管道
|和命令替换$())**的方案,这类方案性能更优;同时最好不使用here-strings<<< ...(会创建临时文件影响性能)。也可提供其他简洁方案作为补充。
解决方案
1. 高性能纯内置方案(无额外子shell/临时文件)
这种方案完全依赖Bash内置语法,没有调用外部命令,性能最优:
explicit_borders="\"\"''()" distinct_border_chars="" # 逐个遍历原字符串的每个字符 for (( i=0; i<${#explicit_borders}; i++ )); do # 提取当前位置的单个字符 char="${explicit_borders:i:1}" # 检查字符是否已在结果字符串中,不存在则追加 if [[ "$distinct_border_chars" != *"$char"* ]]; then distinct_border_chars+="$char" fi done # 验证结果 echo "$distinct_border_chars" # 输出:"'()
核心逻辑:用${string:index:length}语法提取单个字符,通过[[ ... != *...* ]]的模式匹配检查字符是否已存在,不存在则追加到结果变量中。全程无外部进程开销,适合处理大字符串或对性能敏感的场景。
2. 简洁方案(使用外部工具,适合快速编写)
如果对性能要求不高,追求代码简洁,可以用以下几种方式:
方式一:fold + sort -u + tr
explicit_borders="\"\"''()" distinct_border_chars=$(fold -w1 <<< "$explicit_borders" | sort -u | tr -d '\n') echo "$distinct_border_chars" # 输出:"'()
逻辑:fold -w1把字符串拆分成每行一个字符,sort -u排序并去重,tr -d '\n'把多行合并回单行。缺点是会创建多个子shell,性能略低。
方式二:awk 数组去重
explicit_borders="\"\"''()" distinct_border_chars=$(awk -v s="$explicit_borders" '{ for(i=1;i<=length(s);i++){ c=substr(s,i,1) if(!seen[c]++) printf c } }') echo "$distinct_border_chars"
逻辑:利用awk的关联数组seen记录已出现的字符,遍历字符串提取每个字符,未记录过则输出。只创建一个子shell,性能比方式一略好。
内容的提问来源于stack exchange,提问作者Anton Samokat
相关产品推荐
相关产品推荐

