Home > other >  Sorting specific array and print it like tree structure in bash
Sorting specific array and print it like tree structure in bash

Time:06-10

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.

CodePudding user response:

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=$(echo "$i" | cut -d'=' -f1)
    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
  • Related