I have the need to generate a tree view for a list of program and subprogram we actually use.
we have a working script right now (in ksh), but it's take a very long time to achieve (between 3 and 4 hours), and i'm pretty sure it can be done more efficiently/quickly
the actual working script is using two files : 1 : the list of program we actually using (2926 lines) 2 : the list of all programs and subprograms associated to this program (23922 lines)
for better comprehension, this is a representation of the file 2 :
A|B C D E
B|F G
C|J K L
E|
K|Z
L|M N
Z|Y X
the program A call the subprograms B, C, D and E The program B (called by A) call the subprogram F and G The program C (called by A) call the subprogram J K and L etc...
from this two files, we need to write a csv file who represent the tree view of all the programs we use in the first file.
This is the expected output from the previous representation:
A
;B
;;F
;;G
;C
;;J
;;K
;;;Z
;;;;Y
;;;;X
;;L
;;;M
;;;N
;E
To achieve that, this is what we actually do :
part of the main script who call the csv_tree.sh :
#!/bin/ksh
cat program_list | awk -F "|" '{print($2)}' | sort | uniq >program_list.tmp
while read -r line; do
begin=$(echo "$line" | awk -F "|" '{print $1}')
sh csv_tree.sh "$begin" 2>/dev/null
done <$HOME/FISCALITE/OSCAR/FICHIER_IMPORT/FIC_PRG_TREE.tmp
#delete temporary file
rm program_list.tmp
csv_tree.sh :
#!/bin/ksh
#set -x
entry_file="T_SS_PRG_N1"
output_csv_file="${1}_tree.csv"
: >"$output_csv_file"
echo $1 >>"$output_csv_file"
count=0
rank=0
chaine=$(grep -E "^$1" $entry_file | awk '{$1=""}1')
#function loop
loop() {
rank=$((rank + 1))
for prg in $2; do
count=$((count + 1))
if [[ -n $(echo ${prg} | grep ${chaine}) ]]; then
rank=1
fi
# calculate the number of ";" to print in the csv file
separator=$(for ((i = 0; i < rank; ++i)); do echo -n ";"; done)
echo "${separator}${prg}" >>"$output_csv_file"
if [ $(echo ${prg} | egrep "^(X|Y|Z)") != "" ] && [ $(grep "^${prg}" ${entry_file} | awk -F\| '{print $2}' | tr -d ' ') != "" ]; then
echo "${separator};$(grep "^${prg}" ${entry_file} | awk -F\| '{print $2}')" >>"$output_csv_file"
else
loop "${prg}_$count" "$(grep -E "^$prg" $entry_file | awk '{$1=""}1')"
rank=$((rank - 1))
fi
done
}
#begin
loop "$1" "$chaine"
I'm pretty sure we can achieve this with pure awk, but i'm not really into it :/
If someone have some tips or other way to do it better, i'm wide open ^^
In TXR Lisp:
Code looks like:
There is a check in
print-treeagainst circular references, but not against duplicates (diamond references).