Bash3.2下如何排序数组使主元素在前并以树形结构打印
Bash 3.2 无关联数组场景下的数组排序与树形打印方案
问题约束
在Bash 3.2.54版本(无关联数组语法支持)中,对同时包含主元素、子元素的数组排序,要求:
- 主元素格式为
<主名>=<参数串>,必须排在其名下所有子元素之前 - 子元素格式为
<主名>%<命名空间>::<应用名>=<参数串>,同主名下的子元素按字符串自然顺序排列 - 排序完成后按指定树形结构输出结果
原始测试数组定义如下:
myarr=() myarr+=("demo1%myspace1::myapp1=param1#param2#param3") myarr+=("demo1%myspace1::myapp2=param1#param2#param3") myarr+=("demo1%myspace2::myapp1=param1#param2#param3") myarr+=("demo1=param1#param2#param3") myarr+=("demo2%myspace2::myapp1=param1#param2#param3") myarr+=("demo2%myspace2::myapp2=param1#param2#param3") myarr+=("demo2%myspace2::myapp3=param1#param2#param3") myarr+=("demo2=param1#param2#param3")
预期排序后数组顺序:
"demo1=param1#param2#param3" "demo1%myspace1::myapp1=param1#param2#param3" "demo1%myspace1::myapp2=param1#param2#param3" "demo1%myspace2::myapp1=param1#param2#param3" "demo2=param1#param2#param3" "demo2%myspace2::myapp1=param1#param2#param3" "demo2%myspace2::myapp2=param1#param2#param3" "demo2%myspace2::myapp3=param1#param2#param3"
预期树形打印效果:
demo1=param1#param2#param3 | +-- demo1%myspace1::myapp1=param1#param2#param3 +-- demo1%myspace1::myapp2=param1#param2#param3 +-- demo1%myspace2::myapp1=param1#param2#param3 demo2=param1#param2#param3 | +-- demo2%myspace2::myapp1=param1#param2#param3 +-- demo2%myspace2::myapp2=param1#param2#param3 +-- demo2%myspace2::myapp3=param1#param2#param3
实现思路
不需要关联数组,借助系统自带sort命令,通过临时排序键转换即可完成排序,完全兼容Bash 3.2版本:
- 提取每个元素
=之前的前缀部分,判断元素类型:前缀不含%为主元素,含%为子元素 - 为每个元素生成可排序的临时键:
- 主元素临时键结构:
<主名>\t0\t,同主名元素中排序优先级最高 - 子元素临时键结构:
<主名>\t1\t<完整前缀>,同主名子元素优先级低于主元素,且子元素之间按前缀自然序排列
- 主元素临时键结构:
- 将临时键和原元素拼接后送入
sort排序,排序完成后切掉临时键部分,即可得到目标顺序的数组 - 遍历排序后数组,按规则拼接树形前缀打印即可
完整可运行代码
#!/bin/bash # 原始数组初始化 myarr=() myarr+=("demo1%myspace1::myapp1=param1#param2#param3") myarr+=("demo1%myspace1::myapp2=param1#param2#param3") myarr+=("demo1%myspace2::myapp1=param1#param2#param3") myarr+=("demo1=param1#param2#param3") myarr+=("demo2%myspace2::myapp1=param1#param2#param3") myarr+=("demo2%myspace2::myapp2=param1#param2#param3") myarr+=("demo2%myspace2::myapp3=param1#param2#param3") myarr+=("demo2=param1#param2#param3") # 数组排序 sorted_arr=() while IFS= read -r line; do sorted_arr+=("${line#*$'\t'}") done < <( for item in "${myarr[@]}"; do prefix="${item%%=*}" if [[ "$prefix" != *%* ]]; then # 主元素生成高优先级排序键 printf "%s\t0\t\t%s\n" "$prefix" "$item" else # 子元素生成低优先级排序键 main_name="${prefix%%%*}" printf "%s\t1\t%s\t%s\n" "$main_name" "$prefix" "$item" fi done | sort ) # 树形结构打印 current_main="" for item in "${sorted_arr[@]}"; do prefix="${item%%=*}" if [[ "$prefix" != *%* ]]; then [[ -n "$current_main" ]] && echo "" current_main="$prefix" echo "$item" echo " |" else echo " +-- $item" fi done
执行上述脚本即可直接输出符合要求的结果,全程未使用Bash 4.0+才支持的关联数组语法,可在Bash 3.2.54环境下正常运行。
内容的提问来源于stack exchange,提问作者Mubin Icyer
相关产品推荐
相关产品推荐

