1

I have two files:

file1: Is a list of number of interfaces in the switch:

1/1
1/2
1/3
1/4
1/5
.
.

file-2: contains VLAN-ID, VLAN-NAME, Interfaces belonging to that VLAN

1,"vlan-wifi",1/1,1/7,1/8
2,"vlan-admin",1/3,1/5,1/6
3," " ,3/3,1/3

I'm trying to use these files to create a table like:

                    |   interface Switch
VLAN-ID | VLAN-NAME |1/1|1/2|1/3|1/4|1/5|1/6|1/7|1/8|1/9|1/10|...|3/3
    1   |  vlan-wifi| * |   |   |   |   |   | * | * |   |    |   |
    2   | vlan-admin|   |   | * |   | * | * |   |   |   |    |   |
    3   |           |   |   | * |   |   |   |   |   |   |    |   | *

How can I achieve this?

  • 1
    how this record (3rd line) should be displayed? – RomanPerekhrest Aug 9 '17 at 14:27
  • the same as the first and second , we have like 4057 VLAN that mean ( 4057 Line ) – Jcob Aug 9 '17 at 14:47
  • Since your question's title is "Multidimensional arrays Shell Programming and Scripting", does a solution require the use of multidimensional arrays? – Mark Plotnick Aug 9 '17 at 15:56
  • i was thinking about Multidimensional arrays but if there is any soultion will help give me that the same output will be good . – Jcob Aug 9 '17 at 16:07
2

You don't want to use shell loops to process text. Here, it's a typical job for awk:

awk -F '"? *, *"?' '
   !ports_processed {
      port[++ports] = $0; width[ports] = length; next
   }
   FNR==1 {
     printf "                    |   interface Switch\nVLAN-ID | VLAN-NAME "
     for (i = 1; i <= ports; i++) printf "|%s", port[i]
     print ""
   }
   {
     printf "%6d  |%11s", $1, $2
     split("", member)
     for (i = 3; i <= NF; i++) member[$i]
     for (i = 1; i <= ports; i++)
       printf "| %*s", 1 - width[i], (port[i] in member ? "*" : " ")
     print ""
   }' file-1 ports_processed=1 file-2

(here assuming the vlan names don't contain commas or double-quotes or newlines (we'd need to know how they are encoded if those may occur))

To answer the question in the subject, for a shell with multidimensional array support, look at ksh93. It also has csv parsing and writing facilities.

| improve this answer | |
2

You may use the tbl, nroff utilities if you don't want to be bothered with playing around with field widths:

perl -F'\"?,\"?' -lane '
   BEGIN {
      chomp(@A = qx(sort -t/ -k1,1n -k2,2n < $ARGV[0]));
      shift;

      # prepare table for the tbl utiity
      print q/.TS/;
      print join(",", qw/allbox center/, qq/tab(\t);/)       ;
      print join($",  qw/c s c/,         qw/s/ x $#A)        ;
      print join($",  qw/c r/,           qw/c/ x  @A), qw/./ ;
      print join("\t", $,, q/interface switch/);
      print join("\t", qw/VLAN-ID VLAN-NAME/, @A);
   }

    print
join("\t", @F[0,1], map { my $e = $_; (0 < grep { $e eq $_ } @F[2..$#F]) ? q[*] : q[] } @A);

   END { print q/.TE/; }
' file-1 file-2 | tbl - | nroff -Tascii -ms | sed -n '/./!d;$!N;s/.*\n.\(.*\)./\1/p'

Results:

                     |                         interface switch                         
VLAN-ID |  VLAN-NAME | 1/1 | 1/2 | 1/3 | 1/4 | 1/5 | 1/6 | 1/7 | 1/8 | 1/9 | 1/10 | 3/3 
   1    |  vlan-wifi |  *  |     |     |     |     |     |  *  |  *  |     |      |     
   2    | vlan-admin |     |     |  *  |     |  *  |  *  |     |     |     |      |     
   3    |            |     |     |  *  |     |     |     |     |     |     |      |  *  
| improve this answer | |
1

Here is one way to do that using Python. Note that file1 from your question did not appear to be needed, so this script only takes one parameter:

Code:

import sys

filename = sys.argv[1]
vids = {}
intfs = set()
with open(filename, 'rU') as f:
    for line in f:
        vid, vname, vintf = line.strip().split(',', 2)
        vintf = vintf.split(',')
        vids[int(vid)] = (vname.strip('"').strip(), vintf)
        intfs |= set(vintf)

intfs = [(i, len(i)) for i in
         sorted(intfs, key=lambda x: tuple(int(y) for y in x.split('/')))]

max_name_len = max(len(i[0]) for i in vids.values()) + 1

line = ('VLAN-ID |%%%ds' % max_name_len) % (
    'VLAN-NAME' + ' ' * ((max_name_len - 9) / 2))
for intf, width in intfs:
    line += ('|%%%ds' % width) % intf
print(line)

fmt = '%%5s   |%%%ds' % max_name_len
for vid, values in sorted(vids.items()):
    vname, have_intfs = values
    line = fmt % (vid, vname)
    for intf, width in intfs:
        line += ('| %%-%ds' % (width-1)) % (
            '*' if intf in have_intfs else '')
    print(line)

Results:

VLAN-ID | VLAN-NAME |1/1|1/3|1/5|1/6|1/7|1/8|1/10|3/3
    1   |  vlan-wifi| * |   |   |   | * | * |    |   
    2   | vlan-admin|   | * | * | * |   |   |    |   
    3   |           |   | * |   |   |   |   | *  | * 
| improve this answer | |
1

You could do this using bash and arrays as shown:

#!/bin/bash

# store the numerically sorted file1 into array A
A=( $(sort -t/ -k1,1n -k2,2n < file-1) )

# determine the maximum field width by examining the lengths of the 2nd field
# and the string "VLAN-NAME" coming for the header.
maxW=$(
         { echo ',"VLAN-NAME"'; cat < file-2; } |
         cut -d, -f2 | awk '{print length-2}' |
         sort -nr | sed q
      )

# first two fields of the header
B=( "VLAN-ID " "$(printf " %-${maxW}s\n" "VLAN-NAME")" )

# complete header: from array B and the numerically sorted file1 contents
C=( "${B[@]}" "$(IFS="|"; echo "${A[*]}")" )

# display the header
echo "$(IFS="|"; echo "${B[*]}")" |\
sed -e 's/[^[:blank:]]/ /g;s/$/|   interface switch/'
echo "$(IFS="|"; echo "${C[*]}")"

# remaining lines printed
while IFS=, read -ra B; do
   D=(x)
   for arg in "${A[@]}"; do
      case " ${B[*]:2} " in *" $arg "* ) res=* ;; * ) res=\ ;; esac
      var1=${arg//[!\/]/ } D=( "${D[@]}" "${var1/\//$res}" )
   done
   printf "%8s| %${maxW}s|%s\n" "${B[0]}" "${B[1]//\"/}" "$(IFS="|";echo "${D[*]:1}")"
done < file-2

Results

                    |   interface switch
VLAN-ID | VLAN-NAME |1/1|1/2|1/3|1/4|1/5|1/6|1/7|1/8|1/9|1/10|3/3
       1|  vlan-wifi| * |   |   |   |   |   | * | * |   |    |
       2| vlan-admin|   |   | * |   | * | * |   |   |   |    |
       3|           |   |   | * |   |   |   |   |   |   |    | *
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.