Output is key to present our findings and this is even more important in Bash as, for most people, all of this is just raw text on a geek black and white terminal. Also we have to admit that it oftenly takes more time to make a pretty output than to collect the data we are interested in so the output formatting is often treated as an afterthought. I have already shown how to get a nice output using column, all of my scripts have nice outputs but they are specific and the formatting needs to be redone for each script.
This is why I came up with a generic function formatting data from arrays which I have been using for a while now. I will just be using the first 5 lines of a generic /etc/passwd file as an example below.
This is why I came up with a generic function formatting data from arrays which I have been using for a while now. I will just be using the first 5 lines of a generic /etc/passwd file as an example below.
Sourcing the Script
The idea is to keep this function in a dedicated file (let's name it
print_table.sh) and then source it when you need it.[frdenis@myvm ~]$ source print_table.sh [frdenis@myvm ~]$
Preparing the data
The
print_table() function expects a Bash array of comma-separated strings (CSV style). The first element of the array (index 0) is always treated as the header row.Let's take the first 5 lines of
/etc/passwd as our data source:[frdenis@myvm ~]$ head -5 /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync [frdenis@myvm ~]$
Basic Table Usage
To render this as a table, we construct a Bash array, define our header as the first element, replace the ":" delimiters with commas "," and pass the array by reference:
source ./print_table.sh
# Initialize array and create data[0] which is our table header
data=("Username,Password,UID,GID,Comment,Home,Shell")
# Read /etc/passwd line by line and append into the ""data" array
while IFS= read -r line; do
data+=("$(echo "$line" | tr ':' ',')")
done < <(head -5 /etc/passwd)
# Print the table
print_table data
| Username | Password | UID | GID | Comment | Home | Shell |
------------------------------------------------------------------------------
| root | x | 0 | 0 | root | /root | /bin/bash |
| daemon | x | 1 | 1 | daemon | /usr/sbin | /usr/sbin/nologin |
| bin | x | 2 | 2 | bin | /bin | /usr/sbin/nologin |
| sys | x | 3 | 3 | sys | /dev | /usr/sbin/nologin |
| sync | x | 4 | 65534 | sync | /bin | /bin/sync |
------------------------------------------------------------------------------
Customizing Alignment & Row Count
By default, all column contents are centered. You can customize alignment per column by passing a second array containing positional alignment codes:
l: Left alignmentc: Center alignment (default)r: Right alignment
You can also display the total number of processed rows at the bottom by setting
L_SHOW_TOTAL="True".[frdenis@myvm ~]$ cat demo_align.sh #!/bin/bash source ./print_table.sh data=("Username,Password,UID,GID,Comment,Home,Shell") while IFS= read -r line; do data+=("$(echo "$line" | tr ':' ',')") done < <(head -5 /etc/passwd) # Define column alignments: Left, Center, Right, Right, Left, Left, Left align=("l" "c" "r" "r" "l" "l" "l") # Enable total row count display export L_SHOW_TOTAL="True" print_table data align [frdenis@myvm ~]$ ./demo_align.sh | Username | Password | UID | GID | Comment | Home | Shell | ---------------------------------------------------------------------------------- | root | x | 0 | 0 | root | /root | /bin/bash | | daemon | x | 1 | 1 | daemon | /usr/sbin | /usr/sbin/nologin | | bin | x | 2 | 2 | bin | /bin | /usr/sbin/nologin | | sys | x | 3 | 3 | sys | /dev | /usr/sbin/nologin | | sync | x | 4 | 65534 | sync | /bin | /bin/sync | ---------------------------------------------------------------------------------- Number of rows: 5 [frdenis@myvm ~]$
Generating Value Summaries (Comma Lists)
A unique feature of this function is the ability to automatically generate comma-separated summaries of specific columns beneath the table. This is very useful when you want to feed list outputs directly into subsequent script commands or quickly copy/paste them.
Pass the 1-based column indices as parameter 3, and an optional row limit as parameter 4:
[frdenis@myvm ~]$ cat demo_summary.sh #!/bin/bash source ./print_table.sh data=("Username,Password,UID,GID,Comment,Home,Shell") while IFS= read -r line; do data+=("$(echo "$line" | tr ':' ',')") done < <(head -5 /etc/passwd) # Request summary list for Column 1 (Usernames) and Column 3 (UIDs), max 3 rows print_table data "" "1,3" 3 [frdenis@myvm ~]$ ./demo_summary.sh | Username | Password | UID | GID | Comment | Home | Shell | ---------------------------------------------------------------------------------- | root | x | 0 | 0 | root | /root | /bin/bash | | daemon | x | 1 | 1 | daemon | /usr/sbin | /usr/sbin/nologin | | bin | x | 2 | 2 | bin | /bin | /usr/sbin/nologin | | sys | x | 3 | 3 | sys | /dev | /usr/sbin/nologin | | sync | x | 4 | 65534 | sync | /bin | /bin/sync | ---------------------------------------------------------------------------------- Username values (up to 3): root,daemon,bin UID values (up to 3): 0,1,2 [frdenis@myvm ~]$
Scripting Integration: RAW Output Mode
When passing data downstream in pipeline operations, ASCII borders can get in the way. You can bypass the table rendering entirely by enabling
L_RAW="True". This outputs the raw array content without borders or alignments:[frdenis@myvm ~]$ L_RAW="True" ./demo.sh Username,Password,UID,GID,Comment,Home,Shell root,x,0,0,root,/root,/bin/bash daemon,x,1,1,daemon,/usr/sbin,/usr/sbin/nologin bin,x,2,2,bin,/bin,/usr/sbin/nologin sys,x,3,3,sys,/dev,/usr/sbin/nologin sync,x,4,65534,sync,/bin,/bin/sync [frdenis@myvm ~]$
Pro Tip: Using
L_RAW="True" makes your scripts dual-purpose. They can produce human-friendly interactive CLI tables by default, or clean CSV data when piped into other tools.
