Quick
index
main
eev
eepitch
maths
angg
blogme
dednat6
littlelangs
PURO
(C2,C3,C4,
 λ,ES,
 GA,MD,
 Caepro,
 textos,
 Chapa 1)

emacs
lua
(la)tex
maxima
 qdraw
git
lean4
agda
forth
squeak
icon
tcl
tikz
fvwm
debian
irc
contact

An example of a bash script with test blocks (2024)

Here is a screenshot - click on it to enlarge:

It shows a script that I use to convert a series of PDFs into an animated gif. It is explained, as a tool, in this section of one of my pages about Maxima.

1. Bash for people with bad memory: links
2. Examples (and test blocks)
3. Try it!
4. The video


1. Bash for people with bad memory: links

I don't write Bash code often, and I would never be able to remember what the tricks in red below do

and_run      () { echo $*; $*; }
cdr          () { echo ${@:2}; }
add_1zs      () { for i in $*; do echo $i 1-z; done; }
makeboth     () { $ECHO makeflipbook $(cdr $*);
                  $ECHO makeanim $1 $2; }
makeflipbook () { $ECHO qpdf --empty --pages $(add_1zs $(cdr $*)) -- $1; }
makeanim     () {
  $ECHO convert -alpha deactivate ${VERBOSE:+-verbose} \
                -delay $DELAY -loop 0 -density $DENSITY $2 $1
}

without 1) links to the documentation and 2) examples. The links to the documentation appear right above that code in the screenshot - let me copy them here:

# See:
#   (find-bashnode "Environment" "parameter assignments")
#   (find-bashnode "Shell Parameter Expansion" "${@:7}")
#   (find-bashnode "Shell Parameter Expansion" "${PARAMETER:+WORD}")

These links work much better in Emacs than in the browser. If you click on the `")' at the end of one of the `find-bashnode' links above you will see that it goes to a page of the Bash manual, but it "ignores the pos-spec-list"... while in Emacs the second link searches for the first occurrence of "${@:7}", as shown here:

So that solves the first half of my problem - "1) links to the documentation".


2. Examples (and test blocks)

The second half of my problem - "2) examples" - is much trickier. For me it is much easier to test the individual functions in a bash script if it can be used both "as a library" and "as a script"; and the trick that lets it be used in both ways is an

eval "$*"

at the end of the script - see here, or in this screenshot, that also shows its comments and a test block:


3. Try it!

Here's how to try this if you have eev-mode activated:

  • copying the eepitch block below to a buffer in Emacs,
  • type `f8' on each line; note that the bullets - red or not - will still work as red stars,
  • run a (find-anchor ...) with `M-e',
  • go to the test block after the anchor,
  • run the test block with `f8's. Note that the test blocks run in "dry run" mode, and they don't change anything on disk.
 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
rm -fv    /tmp/mkanim1.sh
wget -P   /tmp/ http://anggtwu.net/myqdraw/mkanim1.sh
chmod 755 /tmp/mkanim1.sh
# (find-anchor "/tmp/mkanim1.sh")
# (find-anchor "/tmp/mkanim1.sh" "makeanim-tests")
# (find-anchor "/tmp/mkanim1.sh" "latex-tests")
# (find-anchor "/tmp/mkanim1.sh" "eval-tests")


4. The video

The subtitles in Lua of the video are here.
The rest of this page contains a conversion of the subtitles in Lua
to a slightly more readable format.

0:00 Hi! My name is Eduardo Ochs.
0:02 I'm the author of an Emacs package called eev,
0:05 and this video is associated to my
0:09 presentation in the EmacsConf 2024...

0:12 and the title of this video is:
0:15 "An example of a bash script with test blocks".

0:19 Eev is an obscure Emacs package
0:24 that apparently makes very little sense
0:27 for people in developed countries, and
0:30 makes sense immediately to Brazilians...
0:32 and one of the main themes of my
0:35 presentation at the EmacsConf will be to
0:38 explain that.

0:40 Let me explain what is eev.
0:43 First, an explanation in just three words,
0:46 that is: "Eev is WRONG".

0:48 Now an explanation in more words.
0:51 Eev takes to the extreme the idea that code
0:55 "in production" and code "in a first system",
0:58 in the sense of "The Mytical Man-Month",
1:00 can have very different styles...

1:07 In this presentation I'm going to
1:10 explain test blocks...

1:14 most people in developed countries look at
1:16 test blocks and immediately imagine their
1:19 $EVILBOSS - their internalized $EVILBOSS -
1:22 yelling to them: YOU CAN'T USE THAT IN
1:24 PRODUCTION CODE! YOU'RE FIRED!

1:27 In this video we are going to
1:29 see how to play with existing test
1:31 blocks by downloading a file with test
1:34 blocks in /tmp/...

1:36 because writing your own test blocks
1:39 takes more time, and more imagination,
1:41 and for people in developed countries
1:45 it has a high psychological cost,
1:47 because they feel that test blocks
1:49 are wrong.

1:51 The example is in this link here,
1:53 in this page...
1:56 in a section called "Try it!".

2:02 We just need to copy the eepitch block
2:06 below to a buffer in Emacs - let me do that...
2:11 we can copy it to any read-write buffer...
2:15 let me copy it to the end of this org file...
2:18 I can either copy it in the obvious way
2:21 or I can create a comment block
2:25 and copy it to the comment block.

2:28 And now we need to run this thing here...
2:31 by the way, note that these things here
2:34 are not red stars... they are red bullets,
2:37 but bullets are equivalent to red stars
2:40 in eev, and the explanation for that
2:45 is here, in the docstring for the variable
2:49 `eepitch-regexp'. Anyway...

2:55 I will need to switch to a smaller font.
2:58 If I execute this it downloads
3:01 a certain file in the directory /tmp/,
3:05 it changes the the mode of that file
3:08 to executable,

3:10 and if I execute this sexp hers
3:12 I go to the top of that file....

3:15 it has many explanations here,
3:19 but my suggestion is: in the first
3:23 moment just go to the test blocks -
3:26 for example, this one -
3:28 and execute the test block, and...
3:31 just check that everything works -
3:35 just check that there are no error messages,
3:36 and that it does something interesting
3:38 that we don't understand yet.

3:41 So, it has links to three test blocks...
3:44 this is the second one and this is
3:49 the third one, at the end of the file...

3:52 and in a second moment we can open
3:56 the file again and read the comments...

4:00 and the most important comment is here -
4:02 it explains that many of the functions
4:07 in this file behave differently
4:09 if we set the variable ECHO...

4:14 if we use this thing here, ECHO=echo,
4:22 then this thing
4:28 echoes the commandandargs instead of
4:29 running the commandandargs...

4:31 and if we do ECHO=and_run commandandargs
4:37 then the function echoes the commandandargs
4:40 and runs the commandandargs.

4:43 Let's take a look at the test blocks again.
4:47 Note that in all these lines here...
4:50 they start with ECHO=echo, that makes it
5:00 just echo the external commmands
5:03 that it would run...

5:10 it does some very basic tests here
5:13 and then this line here shows what
5:16 the commmand makeflipbook would run...

5:19 it would call an external command
5:22 called qpdf...

5:22 and this one shows that makeanim
5:27 would run this thing, here that
5:29 would call convert, that is a program
5:32 that comes with ImageMagick...

5:33 and this last one here would run
5:38 two commands, makeflip and makeanim...

5:40 And that's it. I think that it's better
5:43 to stop the video here...
5:45 for more information please see the page
5:48 of the video. That's it! Bye...

5:50 No, no, sorry! Not Bye yet...
5:55 I forgot that this page here also mentions
5:58 the trick that I use
6:02 for remembering these obscure tricks
6:06 with variables in bash...

6:09 and the trick is that my bash file has some
6:13 links like this, that go to the manual
6:15 of Bash, to a certain position
6:19 in the manual... if we run these links -
6:21 if we open these links in the browser
6:24 it just opens a certain page, like this,

6:28 but if we open these links in the...

6:38 for example, here... it opens the page
6:42 of the bash manual and it searches
6:45 for the first occurrence of
6:47 this string here...
6:49 so where are we here,
6:52 parameter assignments...
6:52 and it explains something about
6:55 parameter assignments...
6:58 then this one here goes to an example -
7:00 that also includes the output
7:03 of the example... and so on.

7:09 And that's it! Bye!