How to embed documentation in Bash scripts

Documenting how an application works, its purpose, and its intended usage is really important, even if it is just a simple shell script we are talking about. To ease code maintenance in the most basic cases, documentation can be embed directly inside scripts. In this tutorial we learn how to include Pearl’s Plain Old Documentation syntax (POD) in bash scripts, and how to convert it to various formats using pod2 utilities such as pod2man and pod2html.

In this tutorial you will learn:

  • How to embed POD-formatted documentation in Bash scripts using Heredoc and do-nothing constructs
  • How to convert POD documentation in various formats using pod2 utilities
How to embed documentation in Bash scripts
How to embed documentation in Bash scripts
Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution agnostic
Software Bash, pod2 utilities
Other Privileged access to your Linux system as root or via the sudo command in order to perform system-wide installation of required packages
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

The Heredoc and do-nothing constructs

To embed documentation inside Bash scripts we can make use of two constructs: “Heredoc” and “do-nothing”. The former makes it possible to pass a multi-line input to a specific command. It can be used, for example, to print a multi-line message to standard output, without repeating an echo command multiple times. Instead of writing:

echo "Script usage:"
echo "  myscript [options] argument"
echo ""
echo "Options:"
echo "  -h, --help Show this message"
echo "  -f, --foo This option does foo"
echo "  -b, --bar This option does bar"

We would write:

cat << EOF
Script usage:
  myscript [options] argument

Options:
  -h, --help Show this message
  -f, --foo This option does foo
  -b, --bar This option does bar
EOF

The second snippet, as you can see, is much cleaner (and faster to type). The syntax of an “Heredoc” construct is quite simple: at the left of the << operator we write the command we want to pass the multi-line input to; at the right of the operator, instead, we pass a delimiter, (EOF is often used, but it is just a standard), which marks the end of the Heredoc. If the delimiter is unquoted, variables inside the document are expanded.



We can  use the “Heredoc” construct to embed documentation inside a Bash script. In such situation, however, we don’t want to execute any command: here is where the “do-nothing” construct comes in to play.

In Bash, : is a Null command: it does nothing and always exits successfully (its exist status is always 0). Using the two constructs together, we can embed documentation in shell scripts, the following way:

#!/bin/bash
#
# Bash code goes here
#
exit 0

: << EOF
Script usage:
  myscript [options] argument

Options:
  -h, --help Show this message
  -f, --foo This option does foo
  -b, --bar This option does bar

EOF

Notice I explicitly added an exit 0  instruction just before the documentation section: this is to avoid the shell processing that part when the script is executed.

Using the Perl’s Plain Old Documentation format

In the examples above, the script documentation consisted just of plain text. To produce well formatted documents, however, we can use the Perl’s Plain Old Documentation (POD) format. Here is an example which uses a minimal set of commands:

: << EOF
=pod

=head1 NAME

Here is a brief description of what are script does.

=head1 SYNOPSYS

scriptname [options] argument

=head1 OPTIONS

-h, --help 
    Show this message
        
-f, --foo
    This option does foo
        
-b, --bar 
    This option does bar

=cut

EOF

The first “command paragraph” we used in the example is =pod. It just signals the start of the POD document. In this case it is superfluous, since any command starts the document block; it can be useful, however, when the documentation should start with ordinary text. We then used =head1, which produces a level 1 heading (levels go from 1 to 6). Finally, we used =cut, which signals the end a POD block. A blank line must precede the command, and another one must follow it.

Extracting and generating documentation with pod2 programs

Once we finished describing the functionalities of our script, we can use “pod2” utilities to generate various type of documents such as a roff or HTML pages, which are readable, with the “man” utility and with any web browser, respectively.



On Archlinux and Debian, pod2 utilities are part of the “perl” package, which should be already installed on your system. To explicitly install the package on the former distribution,  however, we can run:

$ sudo pacman -S perl

On the latter, instead, we use apt:

$ sudo apt install perl

On Fedora and other distributions based on it, pod2 utilities ships into separate packages. The “perl-podlators” package includes pod2man, while  “perl-Pod-Html” provides pod2html. We can install them using dnf:

$ sudo dnf install perl-podlators perl-Pod-Html

To generate a roff page, we invoke pod2man and pass the script path as argument, than we redirect the utility stdout to a file:

$ pod2man testscript.sh > testscript.1

We can read the document by running:

$ man ./testscript.1

To make the page available system-wide, so that we can read it without providing its full path, we can copy it into the /usr/share/man/man1 directory.



To generate the HTML version of the document, instead, we use pod2html:

$ pod2html testscript.sh > testscript.html

Conclusions

In this tutorial we learned how to embed documentation inside Bash scripts using “Heredoc” and “do-nothing” constructs. We saw how to use Perl’s Plain Old Documentation syntax, and how to generate roff and HTML-formatted pages based on it, using the pod2man and pod2html utilities.



Comments and Discussions
Linux Forum