For a full list of BASHing data blog posts see the index page.
Auto-incrementing version letters
I have several scripts that auto-increment a number code in a data table. For example, if the code is the first tab-separated field in each of the table's records, then the script that adds the next record would have something like this line:
newcode=$(($(tail -1 table | cut -f1)+1))
In other words, I tail out the last record in the table, cut out the code in that last record, and add one to it with BASH arithmetic.
But what if I wanted to have version letters at the end of mixed letter-number codes, like 101a, 101b, 101c etc? And also wanted to increment version numbers after a letter cycle, like 101c, 101d, 102a, 102b...?
As is usually the case with command-line operations, there's more than one way to do it. This post looks at a couple of solutions to this particular problem, namely incrementing (single) version letters and version numbers on a fixed letter cycle.
A few version letters. If there are six or fewer version letters in the letter cycle (a up to f), an interesting way to increment the letter would be to treat the whole code as a hexadecimal number and add 1 to it. I would do this with AWK as shown:
oldcode="101a"
awk -v old="$oldcode" 'BEGIN {printf("%x\n",strtonum("0X"old)+1)}'
The AWK "strtonum" function converts a string to a number, and if the string has "0x" or "0X" in front, that number will be a hexadecimal. Here the code-as-hexadecimal-number is incremented by 1 and the result printfed as a hexadecimal.
Suppose it's a 4-letter cycle, so that 101a, 101b, 101c, 101d is followed by 102a. In that case, if the last character in the code is "d", AWK needs to add 13 to the code-as-hexadecimal-number:
awk -v old="$oldcode" \
'BEGIN {if (substr(old,length(old),1)=="d") \
{printf("%x\n",strtonum("0X"old)+13)} \
else {printf("%x\n",strtonum("0X"old)+1)}}'
Add 11 for a 6-letter cycle (a-f), 12 for a 5-letter cycle (a-e) etc
See below for a BASH alternative.
More version letters. If the version letters go past "f", for example to "z", the code-as-hexadecimal-number trick won't work. An up-to-date BASH, though, can advance the version letter (in the range a-y) nicely:
oldcode="101j"
echo "${oldcode::-1}$(tr "[a-y]" "[b-z]" <<<"${oldcode: -1}")"
echo here concatenates two strings. The first (${oldcode::-1}) comes from a BASH string operation that returns all but the last character in "oldcode". The second string is the output of a tr command. Here tr is given the string resulting from BASH cutting out the last character in "oldcode" (${oldcode: -1}), namely the version letter. This letter is replaced with the next one in the lowercase alphabet range: tr "[a-y]" "[b-z]".
To increment the code when the version letter is "z", I can just echo the number part of the code plus 1, followed by "a":
if [ "${oldcode: -1}" = "z" ]
then
echo "$((${oldcode::-1}+1))a"
else
echo "${oldcode::-1}$(tr "[a-y]" "[b-z]" <<<"${oldcode: -1}")"
fi
The same BASH construction, with a little tweaking in the tr command, can be used with a small number of version letters, too. Here it's doing the job for the a-d version letter cycle that was "hexadecimaled" above:
All at once. Auto-incrementing adds items to a sequence one by one, in serial order. If you want the whole sequence, BASH is again your friend, with brace expansion:
echo {101..105}{a..d}
Last update: 2022-03-02
The blog posts on this website are licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License