Twitter

Some bash tips -- 19 -- A generic pretty table output function

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.


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 alignment
  • c : 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.



< Previous shell tip / Next shell tip coming soon >

No comments:

Post a Comment

Some bash tips -- 19 -- A generic pretty table output function

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 b...