简体   繁体   中英

Sorting specific array and print it like tree structure in bash

I have an array in bash script like

# myarr contains main elements (i.e. demo1, demo2) and "sub" elements (i.e. demo1%myspace1::myapp1)
# Inserting element in myarr occurs automatically in that order:

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")

And I want to sort it so that "main" element comes before "sub" elements like:

"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"

After that, I want to print the array like:

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

Printing the sorted array is not the problem. Problem is how can I sort the array so that those "main"-elements comes before "sub"-elements?

PS: I use bash 3.2.54 and it doesn't support associative arrays.

The key is to find the main elements from the array, then print each sub-element, sorted.

Here is one way to do it:

#!/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")

for i in "${myarr[@]}"
do
    # Find main elements
    # A main element is something before a =, that does not include a %
    firstelement="${i%=*}"
    if [[ ! "$firstelement" =~ % ]]
    then
        printf '\n%s\n' "$i"
        printf ' |\n'
        # Print the sub elements related to that main element
        printf -- '%s\n' "${myarr[@]}" | grep -E "${firstelement}%.*::" | sort -n | sed -e 's/^/ +-- /'
    fi
done

I defined a main element as an array item that has some text, followed by = , and that does not contain an % sign. Ex. demo1 is a main, demo1%myspace1 is not.

The sed is to add a prefix ( +-- ) to each sub-element.

That code produces the output you wanted:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM