banner

For a full list of BASHing data blog posts, see the index page.     RSS


A record pager built with YAD

To examine an individual record on the command line I previously used a function called recbyfld. This function takes the name of a tab-separated data table and the line number of a record as its arguments. It lists all the fieldnames in the record and their corresponding data items (blank and non-blank), vertically in a terminal. But to see the next or the previous record, I had to run recbyfld again with the next or previous line number.

The script below, called "yadrex", is my new record-by-record pager. It shows fieldnames and data items in a tidy-looking YAD window (screenshot below), and the three buttons at bottom right allow a choice between next record, previous record and quitting (with keyboard shortcuts Enter = next record and Esc = quit). Like recbyfld, "yadrex" takes the filename and an initial line number as arguments, and the third argument is the number of columns to be displayed:

term
 
yad

The rest of this post explains how "yadrex" works.

#! /bin/bash
 
fieldnames=$(awk -F"\t" 'NR==1 {for (i=1;i<=NF;i++) {printf " --field="$i}}' "$1")
 
nr="$2"
 
while true; do
 
awk -v goto="$nr" 'NR==goto' "$1" | tr '\t' '\n' | \
while read line; do echo "$line"; done \
| yad --center --columns="$3" --form $(echo "$fieldnames") \
--button="Quit":1 --button="Previous record":2 --button="Next record":0 \
> /dev/null
 
case $? in
1) exit 0;;
2) nr=$(($nr-1)) && continue;;
0) nr=$(($nr+1)) && continue;;
252) exit 0;;
esac
 
done
 
exit 0

Update. The script has been updated to make the number of columns displayed by "yadrex" something that's specified in the third argument, and "width" doesn't have to be specified. Without this tweak and with a very large number of fields, the YAD buttons disappear off the bottom of the screen!

The script starts with AWK selecting the header line (NR==1) of the tab-separated (-F"\t") data table ("$1"). AWK then works through the line field by field (for (i=1;i<=NF;i++)) and prints [space]--field=[fieldname] for each field. I use AWK's "printf" without a newline to ensure that all the results go on one line (see screenshot below). This one-line string is just what YAD needs to create the item labels (see YAD screenshot above), and the string is saved as the variable "fieldnames" for later feeding to YAD. Note that the number of fields in the data table doesn't have to be specified in advance. However many fields there are, AWK will print [space]--field=[fieldname] for each of them and YAD will process that code.

fieldnames

The next line of the script assigns the second argument (line number) to the variable "nr".

The script now starts an endless while true loop. In the loop, AWK selects line number "nr" and prints it. The print is piped to tr, which converts the tab-separated line of data items to a vertical list. This list is then piped to YAD item-by-item with a while read line loop.

YAD now has items and item labels, so all it needs is instructions on what to do with them. I place a YAD form (--form) in the centre of my screen (--center) and distribute the form over a specified number of columns (--columns="$3") for neatness. There won't be any output from this YAD form in my terminal, because any stdout is sent to the bottomless pit called /dev/null.

YAD is now displaying the selected record (YAD screenshot above). What happens next depends on which button is clicked or which keys are pressed, and is decided in a case construction. Pressing ESC or clicking the "X" at top right in the YAD window sends a return value of 252 (hard-coded in YAD) to the shell, which responds by closing the script. The script can also be exited by clicking the "Quit" button (return value 1). Clicking "Next record" (return value 0) or pressing "Enter" (or "Ctrl+Enter" in some YAD versions) causes the shell to add 1 to "nr" and restart (continue) the while true loop with the incremented value of "nr". Clicking "Previous record" (return value 2) does the same, but subtracts 1 from "nr".

The script works well, although it pages by first closing the existing YAD window and then opening a new one, which makes my screen "flickery" if I page rapidly. A BASH wizard could probably work out how to keep the window open while paging, through use of the --cycle-read option for YAD forms. I tried a few approaches to the --cycle-read construction but none of them succeeded and the code was getting seriously complicated. Never mind: the "yadrex" script is just what I need for the occasional What does the next record or two look like? moments!


Last update: 2018-09-09