tablizer - a tool to manipulate tabular output of shell commands

Last year I switched departments and am working now with k8s, the cloud and all the new fancy stuff. Most of the time I work on the commandline. I cannot say I am not happy with the new assignment, but some things k8s annoy me anyway.

Here’s an example:

kgpw|grep 5fc
connecttest10-pgbenchclient-5fcb6888c9-28csx              0/1     ContainerCreating   0                 8d     <none>       kind-worker2         <none>           <none>
connecttest10-pgbenchclient-5fcb6888c9-4cbh4              0/1     ContainerCreating   0                 8d     <none>       kind-worker3         <none>           <none>
connecttest10-pgbenchclient-5fcb6888c9-bh644              0/1     ContainerCreating   0                 8d     <none>       kind-worker3         <none>           <none>
connecttest10-pgbenchclient-5fcb6888c9-bp9sf              0/1     ContainerCreating   0                 8d     <none>       kind-worker2         <none>           <none>
connecttest10-pgbenchclient-5fcb6888c9-lw8kp              0/1     ContainerCreating   0                 8d     <none>       kind-worker3         <none>           <none>

(kgpw == kubectl get pod -o wide)

The first problem is, that this output is waaaay to wide. Sometimes I get outputs which so wide, that even on a 3440x1440 monitor every line is being broken. The result is unreadable. I even once deleted the wrong database just because of this mess.

The other issue is that if you use something like |grep then the headers go missing as can be seen in the example above.

I hate this fucking behavior.

Of course, it might be possible to circumvent all these (and more) issues using tools like awk etc. And to make it clear: i tried this in the beginning. But the shell function I used for this purpose got more and more unflexible, it grew larger and larger up to the point that it wasn’t maintainable anymore.

Enter tablizer.

Since working in the cloud, learning Go was a must anyway. And I am a practical learner, that is I need some usefull project to learn a new language. This annoyance here came in to the “rescue”.

By using tablizer I can combine tools like egrep, awk, sed, sort and column in one handy and easy to use tool. I don’t use it directly most of the time, but rather put it into handy shell aliases.

Here’s the usage message of it:

Usage:
  tablizer [regex] [file, ...] [flags]

Operational Flags:
  -c, --columns string     Only show the speficied columns (separated by ,)
  -v, --invert-match       select non-matching rows
  -n, --no-numbering       Disable header numbering
  -N, --no-color           Disable pattern highlighting
  -H, --no-headers         Disable headers display
  -s, --separator string   Custom field separator
  -k, --sort-by int        Sort by column (default: 1)

Output Flags (mutually exclusive):
  -X, --extended           Enable extended output
  -M, --markdown           Enable markdown table output
  -O, --orgtbl             Enable org-mode table output
  -S, --shell              Enable shell evaluable ouput
  -Y, --yaml               Enable yaml output
  -C, --csv                Enable CSV output
  -A, --ascii              Default output mode, ascii tabular

Sort Mode Flags (mutually exclusive):
  -a, --sort-age           sort according to age (duration) string
  -D, --sort-desc          Sort in descending order (default: ascending)
  -i, --sort-numeric       sort according to string numerical value
  -t, --sort-time          sort according to time string

Other Flags:
      --completion <shell> Generate the autocompletion script for <shell>
  -d, --debug              Enable debugging
  -h, --help               help for tablizer
  -m, --man                Display manual page
  -v, --version            Print program version

So, let’s work through an example. Say we want to get a list of pods, their status and the node each pod is running on AND only pods matching some pattern shall be printed.

The very first thing you do, is execute the original command again (without any |grep after it!) and put | tablizer behind it. You’ll get something like this (shortened):

kgpw | tablizer
NAME(1)                                                	READY(2)	STATUS(3)        	RESTARTS(4)     	AGE(5)	IP(6)     	NODE(7)           	NOMINATED NODE(8)	READINESS GATES(9) 
connect11test10-benchtest-pgbenchclient-b68d988b8-9vks5	0/1     	ContainerCreating	0               	7d6h  	<none>    	kind-worker3      	<none>           	<none>            	
connect11test10-benchtest-pgbenchclient-b68d988b8-dpq8g	0/1     	ContainerCreating	0               	7d6h  	<none>    	kind-worker2      	<none>           	<none>            	
connect11test10-benchtest-pgbenchclient-b68d988b8-f2dpn	0/1     	ContainerCreating	0               	7d6h  	<none>    	kind-worker3      	<none>           	<none>            	
connect11test10-benchtest-pgbenchclient-b68d988b8-fjhk4	0/1     	ContainerCreating	0               	7d6h  	<none>    	kind-worker2      	<none>           	<none>            	
connect11test10-benchtest-pgbenchclient-b68d988b8-m64z7	0/1     	ContainerCreating	0               	7d6h  	<none>    	kind-worker2      	<none>           	<none>
[..]

This looks pretty unchanged to the original output, but the headers are now numerized. Armed with that knowledge we can now reduce the output to the columns we want to see by using the -c option:

kgpw | tablizer -c 1,3,7
NAME(1)                                                	STATUS(3)        	NODE(7)            
connect11test10-benchtest-pgbenchclient-b68d988b8-9vks5	ContainerCreating	kind-worker3      	
connect11test10-benchtest-pgbenchclient-b68d988b8-dpq8g	ContainerCreating	kind-worker2      	
connect11test10-benchtest-pgbenchclient-b68d988b8-f2dpn	ContainerCreating	kind-worker3      	
connect11test10-benchtest-pgbenchclient-b68d988b8-fjhk4	ContainerCreating	kind-worker2      	
connect11test10-benchtest-pgbenchclient-b68d988b8-m64z7	ContainerCreating	kind-worker2      	
connecttest10-benchtest-pgbenchclient-8bb8ff5d8-52xg5  	ContainerCreating	kind-worker3      

Now we add our search pattern and we also add -n to hide the numberization:

kgpw|tablizer -c 1,3,7 -n 5fc 
NAME                                        	STATUS           	NODE         
connecttest10-pgbenchclient-5fcb6888c9-28csx	ContainerCreating	kind-worker2	
connecttest10-pgbenchclient-5fcb6888c9-4cbh4	ContainerCreating	kind-worker3	
connecttest10-pgbenchclient-5fcb6888c9-bh644	ContainerCreating	kind-worker3	
connecttest10-pgbenchclient-5fcb6888c9-bp9sf	ContainerCreating	kind-worker2	
connecttest10-pgbenchclient-5fcb6888c9-lw8kp	ContainerCreating	kind-worker3

That’s pretty much it. Now put this commandline into some handy alias and you’re good to go. There are many more options: you can let tablizer generate markdown or orgmode tables, you can let it print extended output like \x in psql, yaml mode etc etc. There are usefull sorting options, you can even sort by kubernetes age output.

Also, you’re not limited to shell output, using the -s option you can use the tool to process CSV files (or anything other looking tabular with headers), you can also generate valid CSV for that matter.

If you’re working on the commandline every day in a cloud environment and are annoyed by too large and confusing outputs, then give tablizer a try. It’s easy to install, there are precompiled binaries for the most popular architectures without dependencies. There are also tarballs containing a proper installer with a manual page if you’re into this.

Read the manual page to learn more about tablizer.

#shell

↷ 19.07.2023