Hi everyone,
I have been working on a pretty laborious shellscript (with bash) the last couple weeks that parses my firewall policies (from a Juniper) for me and creates a nifty little columned output. It does so using awk on a line by line basis to pull out the appropriate pieces of each policy to build the proper output later.
Unfortunately, not all the data that I extract from the text file comes out to the same length so often times my columns are all over the place.
I've been searching left and right, but cannot find of a good simple way to do this. I am beginning to think I will have to create some sort of function to find the length of each individual column before printing the data, but I am not sure if this is possible.
I am currently using the following code:
echo -e "From: \t"$frm_Zone"\tTo:\t"$to_Zone
echo -e $pol_Id"\t"$src_Address"\t\t"$dst_Address"\t\t"$pol_Service"\t"$pol_Action"\t"$pol_Name
#finding the array with the largest index
#so we now how many times to run the for loop
lnAddy=`echo ${#srcAddyArray
[*]}`
lnSrc=`echo ${#dstAddyArray
[*]}`
lnSvc=`echo ${#serviceArray
[*]}`
max2 $lnAddy $lnSrc
temp=$?
max2 $temp $lnSvc
longest=$?
for (( i = 0; i < longest; i++ )) do
echo -e "\t"${srcAddyArray[$i]}"\t"${dstAddyArray[$i]}"\t"${serviceArray[$i]}
done
The output unfortunately ends up looking something like this:
From: Trust-cs To: Untrust-Firn
615 Any mail.acast.foo.com tcp-6777 (wo 85073) Permit Nat SRC wo 85073
69.xxx.xxx.1 mail.gort.org tcp-6788 (wo 85073)
75.123.44.1 my.mctabbs.net tcp-8008 (wo 85073)
From: Trust-cs To: DMZ-test
596 Any 69.xxx.xxx.31 TCP-15888 Permit
tables.noc.wow.org mages.icecrown.com tcp-16888
TCP-17888
UDP-17888
UDP-18888
Is it possible to get the output to be spaced appropriately so it doesn't get clobbered if some lines are longer than others?
Any help would be greatly appreciated! If you need to see the rest of the script or some sample data, please let me know and I'll be happy to assist.
Thanks in advance!
Hi, cixelsyd:
Welcome to the forums. I believe what you want to check out is printf. It is usually a shell built-in, but is probably also available as a standalone executable if not builtin. printf is also available as a function within AWK. You can use it to print out fixed width columns regardless of the string argument's length.
An example showing how to print out two 10 character wide, left-justified columns (separated by a space):
$ one=1 four=4444 six=666666 nine=999999999
$ echo $one $four; echo $six $nine
1 4444
666666 999999999
$ printf '%-10s %-10s\n' $one $four; printf '%-10s %-10s\n' $six $nine
1 4444
666666 999999999
Note that if the string is wider than the column's width (in this case 10), the column will expand to accomodate the data and break the formatting. So, you'll need to choose a width that should seldom if ever be exceeded, or truncate the string to 10 prior to passing it to printf.
In bash, you should definitely have printf builtin. Perhaps something similar to the following will work for you:
printf '\t%-25s %-25s %-25s\n' "${srcAddyArray[$i]}" "${dstAddyArray[$i]}" "${serviceArray[$i]}"
Regards,
Alister
Alister,
Thank you so much for your help! That did exactly the trick. I modified the script to the following:
echo -e "From: \t"$frm_Zone"\tTo:\t"$to_Zone
printf '%-5s %-20s %-20s %-20s %-15s %-10s\n' $pol_Id $src_Address $dst_Address "$pol_Service" "$pol_Action" "$pol_Name"
#finding the array with the largest index
#so we now how many times to run the for loop
lnAddy=`echo ${#srcAddyArray
[*]}`
lnSrc=`echo ${#dstAddyArray
[*]}`
lnSvc=`echo ${#serviceArray
[*]}`
max2 $lnAddy $lnSrc
temp=$?
max2 $temp $lnSvc
longest=$?
for (( i = 0; i < longest; i++ )) do
printf '%-5s %-20s %-20s %-20s\n' "" "${srcAddyArray[$i]}" "${dstAddyArray[$i]}" "${serviceArray[$i]}"
done
I ended up having to print one blank column so it lined up properly, but now the output is exactly how I wanted:
From: Trust-cs To: Untrust-Firn
615 Any mail.acast.xxxx.xxx tcp-6777 (wo 85073) Permit Nat SRC wo 85073
69.xx.xxx.1 mail.xxxxxxx.edu tcp-6788 (wo 85073)
75.xxx.44.1 my.xxxxxx.edu tcp-8008 (wo 85073)
From: Trust-cs To: DMZ-acad
596 Any 69.xx.xxx.31 TCP-15888 Permit
tables.noc.xxxx.xxx mages.icecrown.com tcp-16888
TCP-17888
UDP-17888
UDP-18888
Thank you so much for your help!
This makes sense.
$ diff newfile oldfile
2,3c2
<
< printf '%-5s %-20s %-20s %-20s %-15s %-10s\n' $pol_Id $src_Address $dst_Address "$pol_Service" "$pol_Action" "$pol_Name"
---
> echo -e $pol_Id"\t"$src_Address"\t\t"$dst_Address"\t\t"$pol_Service"\t"$pol_Action"\t"$pol_Name
19,20c18
< printf '%-5s %-20s %-20s %-20s\n' "" "${srcAddyArray[$i]}" "${dstAddyArray[$i]}" "${serviceArray[$i]}"
<
---
> echo -e "\t"${srcAddyArray[$i]}"\t"${dstAddyArray[$i]}"\t"${serviceArray[$i]}