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

Form text and placeholders

The three miscellaneous demonstrations in this post all have something to do with form text and placeholders. Form text is text saved as a template and variable text is added as needed. A good example is a form letter. The basic text of the letter is stored as a document, and the date, the addressee and the salutation are variable bits that get added before the letter is sent. Sometimes the missing text is marked with a placeholder like "{DATE}".

Form text and placeholders in plain-text documents are easy to deal with on the command line, as shown below.

Routine emails. Do you get a lot of end-of-year "Season's Greetings" emails that you could answer with form text? The script below takes the template text file "2021" in /home and replaces the addressee, email date and comment placeholders with entries in a YAD form. The finished form text is then sent to the primary (X) clipboard with the xclip utility, from where it can be middle-click-pasted into a reply email. The script could be launched with a desktop icon or a keyboard shortcut.

Template file "2021":
Many thanks for your holiday greetings of DATE and your good wishes for the new year. I wish you all the best for 2021, and here's hoping it's better than 2020 was!

yad --form \
--field=Name \
--field="Email date" \
--field=Comment \
| awk -F"|" 'FNR==NR {split($0,a,"|"); next} \
{sub("NAME",a[1]); sub("DATE",a[2]); \
if (a[3] != "") {sub("COMMENT",a[3])} else {sub("COMMENT","")}; \
if (NF) print}' - 2021 \
| xclip


For a simple introduction to the YAD form dialog, see this Linux Rain blog post from 2014. By default, YAD's form output is the entries (empty string or not) with a pipe (|) after each one.
The YAD output string is piped to AWK, which works on 2 files using the FNR==NR trick. The first "file" is the YAD output from stdin, represented by the argument "-". AWK splits the string into 3 components based on the pipe character and stores each component in the array "a", with the serial numbering a[1] (for "Name"), a[2] ("Email date") and a[3] ("Comment").
AWK next moves to the file "2021" and processes it line by line. If it finds "NAME" in the line it replaces "NAME" with the YAD name entry in a[1], and if it finds "DATE" it replaces "DATE" with the YAD date entry in a[2]. AWK next tests to see if there's something other than an empty string in a[3] ( if (a[3] != "") ). If there is, AWK replaces "COMMENT" with a[3]. If there's no comment string, AWK deletes "COMMENT". Finally, AWK checks to see if the current line contains something, and if so it prints the line (if (NF) print). If it's the line with "COMMENT" and "COMMENT" had been deleted, the line isn't printed.
AWK's output is piped to the xclip utility for middle-click pasting.

Digital gardening diary. This script adds a dated entry to a plain-text file called "garden" in the "Misc" folder in /home. The YAD form has spaces for short notes on the weather and any work done in various parts of the garden. The template text is included in an AWK command.

day=$(date +"%e %b %Y")
entry=$(yad --form \
--field=Date:RO \
--field="Weather" \
--field="Fruit trees" \
--field="Bed 1" \
--field="Bed 2" \
--field="Bed 3" \
--field=Other \ "$day" "" "" "" "" "")
if [ -z "$entry" ]; then
awk -F"|" '{print "\n"$1"\nWeather: "$2"\nFruit trees: "$3"\nBed 1: "$4"\nBed 2: "$5"\nBed 3: "$6"\nOther: "$7"\n\n-----"}' <<<"$entry" >> ~/Misc/garden

garden-form garden-diary

I've formatted the current date with date and used it in a read-only (grayed-out) field in the dialog. The YAD output is stored in the entry variable. There's an escape if/else which exits the script if the YAD output is null, otherwise the AWK command that follows would add an undated entry to the "garden" file if the YAD dialog is cancelled, with only the template text.
(No such escape was needed in the email script above, because the script's output only goes to the primary clipboard, which gets re-filled when some other text is highlighted.)
If YAD output exists, it's fed to AWK, whose only instruction is to print the template text pieces and the corresponding fields from the YAD string, with an initial newline and a following "spacer" of a blank line and 5 hyphens.
The current date could also be added to "garden" in the AWK command, but my preference is to make it visible in the YAD dialog and part of the YAD output.

Simple mail merge. I'd like to make text blocks (as for addressing letters) for the six people listed in the tab-separated file "people" (below).

022KibeAgni418, Thflr, Golden Chambers, New Link Rd, Opp Citi Mall, Andheri (west)MumbaiMaharashtraIndia400053
023KrugerJohannesMarseiller Strasse 66SchlehdorfFreistaat BayernGermany82444
024MirelesHidalgoSan Andrés 51BañobárezSalamancaSpain37271
025NishRasheeda45, Pushp ViharNew DelhiDelhiIndia110062
036TraugottFlorianBayreuther Strasse 6FrankfortBrandenburgGermany15204
047WindhorstMagdaRue de Virton 461EugiesHaibautBelgium7340

Because each person is on a separate line and each data item is in a separate, tab-separated field, I can build a text block simply by telling AWK to format the fields in each line with "virtual placeholders" like this:

Last_name First_name
State Postcode

I can upper-case the lastname and the country at the same time, as shown below for Sr Mireles (line 4 in "people"):


However, text blocks and labels usually have a fixed width, and it looks like Mr Kibe's street address (line 2) would make the block too wide. I can fix that by using the fmt command to split long lines (-s) and force a line limit of 30 characters (-w 30). I'll also double-space the text blocks in the printf formatting (with \n\n):

awk -F"\t" 'NR>1 {printf("%s %s\n%s\n%s\n%s %s\n%s\n\n", \
$3,toupper($2),$4,$5,$6,$8,toupper($7))}' people | fmt -s -w 30


Last update: 2021-01-13
The blog posts on this website are licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License