Home > database >  How can I use bash to show a hierarchy structure?
How can I use bash to show a hierarchy structure?

Time:11-04

I have a csv file like below. The ID is the unique identifier of each employee, and the MANAGERID is the ID of his/her manager.

id,managerid,firstname,lastname,dob,address
1,0,John,A,1976-01-01,some where
108,12,Tom,B,1996-01-01,some where
85,12,Jerry,C,1975-01-01,some where
12,1,Winsor,D,1984-01-01,some where
16,85,Smith,H,1977-01-01,some where
100,0,Ray,G,1999-01-01,some where
22,100,Albert,B,1980-01-01,some where
17,22,Robert,J,1980-01-01,some where
21,22,Linda,K,1981-01-01,some where
35,17,Lily,J,1968-01-01,some where
101,0,Sam,A,1995-01-01,some where
105,101,Liz,Z,1988-08-08,earth

I want to use a bash command/script to print out the structure, like a tree. The top manager is the root, following by the department manager and the employees of the department. The ID & name of the top manager should also be listed aside the employees.

I dont have a clue how to do this yet.

The expected output should be like this.

1:John A(1:John A)
 12:Winsor D(1:John A)
 -85:Jerry C(1:John A)
 --16:Smith H(1:John A)
 -108:Tom B(1:John A)
100:Ray G(100:Ray G)
 22:Albert B(100:Ray G)
 -21:Linda K(100:Ray G)
 -17:Robert J(100:Ray G)
 --35:Lily J(100:Ray G)
101:Sam A(101:Sam A)
 105:Liz Z(101:Sam A)

Any help would be much appreciated!

CodePudding user response:

If you have python installed, you can try this code. It works in python2 & python3.

tree.py:

import sys

class Employee:
  def __init__(self, id, pid, name):
    self.id = id
    self.pid = pid
    self.name = name
    self.level = 0
    self.managerinfo = self.id ": " self.name

def printlist(rlist): 
  for e in rlist:
    print(' '.ljust(e.level 1,'-') e.id ":" e.name "(" e.managerinfo ")")

def insone(mylist, id, newe):
  idx=0
  for e in mylist:
    idx =1
    if e.id == id:
      newe.level = e.level 1
      newe.managerinfo = e.managerinfo
      mylist.insert(idx,newe)
      #print('Insertint ' newe.id ':' newe.name ' after ' e.id ':' e.name)
      return True
  return False

def sortlist(sorted,unsorted):
  #print("begin:" str(len(unsorted)))
  if len(unsorted)<=0:
    return
  for u in unsorted:
    if u.pid == '0':
      sorted.append(u)
      unsorted.remove(u)
    else:
      if insone(sorted, u.pid, u):
        unsorted.remove(u)
  #print("end:" str(len(unsorted)))
  sortlist(sorted,unsorted)

if __name__ == "__main__":

  file1 = open(sys.argv[1], 'r')
  Lines = file1.readlines()

  rawlist=[]
  line=0
  for row in Lines:
    line =1
    if line>1:
      a = row.strip().split(',')
      rawlist.append(Employee(a[0],a[1],a[2] " " a[3]))

  sortedlist = []
  sortlist(sortedlist,rawlist)

  printlist(sortedlist)

Then run this,

[ rquery]$ python tree.py samples/organization.csv
 1:John A(1: John A)
 -12:Winsor D(1: John A)
 --85:Jerry C(1: John A)
 ---16:Smith H(1: John A)
 --108:Tom B(1: John A)
 100:Ray G(100: Ray G)
 -22:Albert B(100: Ray G)
 --17:Robert J(100: Ray G)
 ---35:Lily J(100: Ray G)
 --21:Linda K(100: Ray G)
 101:Sam A(101: Sam A)
 -105:Liz Z(101: Sam A)

Alternatively, if you can download rq, it can complete this task within one command line.

[ rquery]$ ./rq -n -q "p d/,/ | s switch(comparenum(@level,0),1,' ','') pad('-',@level-1) id ':' firstname ' ' lastname '(' root(id) ':' root(firstname) ' ' root(lastname) ')' | h k:id;p:managerid" samples/organization.csv
1:John A(1:John A)
 12:Winsor D(1:John A)
 -85:Jerry C(1:John A)
 --16:Smith H(1:John A)
 -108:Tom B(1:John A)
100:Ray G(100:Ray G)
 22:Albert B(100:Ray G)
 -21:Linda K(100:Ray G)
 -17:Robert J(100:Ray G)
 --35:Lily J(100:Ray G)
101:Sam A(101:Sam A)
 105:Liz Z(101:Sam A)

CodePudding user response:

Unless your actual input contains circular management relations between employees, this should work fine with GNU awk:

$ cat tst.awk
BEGIN {
  FS = ","
}

{
  mgrs[$2]
  mgmt[$2][$1]
  name[$1] = $1 ":" $3 " " $4
}

END {
  tree(0, 1, "", " ")
}

function tree(mgr, _top, arm, ext) {
  if (!(mgr in mgrs))
    return

  for (mge in mgmt[mgr]) {
    if (_top)
      top = mge

    print arm name[mge] "(" name[top] ")"

    tree(mge, 0, arm ext, "-")
  }
}
$ awk -f tst.awk file 
1:John A(1:John A)
 12:Winsor D(1:John A)
 -85:Jerry C(1:John A)
 --16:Smith H(1:John A)
 -108:Tom B(1:John A)
100:Ray G(100:Ray G)
 22:Albert B(100:Ray G)
 -17:Robert J(100:Ray G)
 --35:Lily J(100:Ray G)
 -21:Linda K(100:Ray G)
101:Sam A(101:Sam A)
 105:Liz Z(101:Sam A)
  • Related