70

Is there a convention for documenting shell scripts' parameters?

For example:

#!/usr/bin/env bash

# <description>
#
# Usage:
#  $ ./myScript param1 [param2]
# * param1: <description>
# * param2: <description>

A few things I don't like about this particular template:

  • the script's file name (myScript) appears within the file itself
  • parameter description seems weird
  • the leading space before $ is visually useful, but can lead to confusion in languages with block comments, causing some validation tools to complain about mixed/inconsisent indentation (e.g. spaces in this block, tabs for code - provided one prefers tabs, of course)

Are there any guidelines on this?

1

8 Answers 8

72

Traditionally you document your arguments in the usage() function:

#!/bin/bash

programname=$0

function usage {
    echo "usage: $programname [-abch] [-f infile] [-o outfile]"
    echo "  -a      turn on feature a"
    echo "  -b      turn on feature b"
    echo "  -c      turn on feature c"
    echo "  -h      display help"
    echo "  -f infile   specify input file infile"
    echo "  -o outfile  specify output file outfile"
    exit 1
}

usage
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks to everyone for their responses. While they are all fairly Bash-specific, they're useful nevertheless. I'll have to think about how best to implement this (as a common pattern) in Python, Perl, Ruby etc.
Having thought about this a little more, the in-code documentation is required as well, as it serves a slightly different purpose. So I will adopt the automated usage info, but would still appreciate some advice on the original issue.
I have a question. Why should you use exit code 1 here?
@LRDPRDX Because if you're printing usage, you most likely did not complete the function of the program, so you return failure. A great example is if not supplying any arguments causes the script to call usage, and another script called this script, intending to supply arguments, but not doing so due to a bug, it's ideal for this script to communicate to the calling script that it failed to do anything.
@DuncanXSimpson What if the arguments-supplier program is intended to print usage at some point? It is probably better to call exit 1 only in handled unexpected situations rather than in the quite expected situation of asking for help. I would say that printing self usage is part of the function of a program. Also, I'd expect a usage function to just print usage, not to terminate the program, so exit should be called outside usage.
|
36

I would recomment using a heredoc:

usage () {
    cat <<HELP_USAGE

    $0  [-a] -f <file>

   -a  All the instances.
   -f  File to write all the log lines
HELP_USAGE
}

instead of:

echo "$0  [-a] -f <file>"
echo
echo "-a  All the instances."
echo "-f  File to write all the log lines."

I think it is way cleaner than all these echo lines.

3 Comments

I think this solution is the most beautiful of all the answers. Thanks
I avoid heredoc only because it destroys indentation.
@DávidHorváth You may indent the heredoc contents by adding a "-" to the stop token : tldp.org/LDP/abs/html/here-docs.html#LIMITSTRDASH
33

I usually wrap my usage in function so I can call it from a -h param etc.

#!/bin/bash
usage() {
    cat <<EOM
    Usage:
    $(basename $0) Explain options here

EOM
    exit 0
}

[ -z $1 ] && { usage; }

4 Comments

I fixed the here doc for you by indenting the script. I don't understand the [ -x $1 ] (if the first argument isn't the path to an executable file, produce usage?); the braces and semicolon around the invocation are redundant too.
Doh, didn't notice the x; changed it to the z it wanted to be.
I guess the braces are habit so I can include an error message along with the check depending on the check. Thanks for the indenting code trick!
You need to quote that $1 since it could contain spaces and [ is just a regular program that takes -z as the first argument, ] last. If $1 contained "x -o 1 -eq 1", it would always show the usage information.
16

The Vim bash IDE that does this:

#!/bin/bash
#===============================================================================
#
#          FILE:  test.sh
#
#         USAGE:  ./test.sh
#
#   DESCRIPTION:
#
#       OPTIONS:  ---
#  REQUIREMENTS:  ---
#          BUGS:  ---
#         NOTES:  ---
#        AUTHOR:  Joe Brockmeier, [email protected]
#       COMPANY:  Dissociated Press
#       VERSION:  1.0
#       CREATED:  05/25/2007 10:31:01 PM MDT
#      REVISION:  ---
#===============================================================================

3 Comments

Ugh, looks like the identification section of COBOL program. shivers.
That looks interesting - will consider that, thanks! (Though the problem with multi-line comments - as in heredoc - remains.)
I always use "#:" for this meta-comments so I can separate them from the implementation comments.
8

I would recommend making your script automatically print usage (if it shouldn't be run without arguments):

#!/usr/bin/env bash

if [ $# == 0 ]; then
    echo "Usage: $0 param1 [param2]"
    echo "* param1: <description>"
    echo "* param2: <description>"
fi

1 Comment

You can use $# as a shortcut for the argument count.
3

I would rather write:

Usage: `basename $0` [option1]|[option2] param1
  Options:
   - option1:  .....
   - option2:  .....
  Parameters:
   - param1:   ..... 

Try to look at the way help is formatted for standard UNIX utilities (ls --help, for instance)

Comments

0

Based on @eddy's excellent answer here's the version that takes care of multiple arguments (in this example 2)

#!/bin/bash

usage() {
    cat <<EOM
Usage: $(basename $0) <username> <myproject> 
where 
  <username> is your user name
  <myproject> is your project's name
EOM
    exit 1
}

[ $# != 2 ] && { usage; }
for arg in "$@"
do
    [ -z "$arg" ] && { usage; }
done

The double check of the length of the array of arguments ([ $# != 2 ]) as well as on arguments to be not null ([ -z "$arg" ]) is needed to take care of empty strings given as arguments.

Comments

0

I tend to use a Doxygen style for file headers:

#!/bin/bash
##
 #  @file       filename.sh
 #  @brief      Brief description
 #
 #>>>Usage
 #? 
 #? $0 [OPTIONS]
 #? 
 #? -?, -h, --help      Display this help and exit
 #? 
 #<<<Usage
 #
 #  @version    2024-07-05T22:40:33
 ##

# Print header starting with Doxygen codes
grep -E '^ *# *@' $0 | cut -f 2- -d '@'

#----------------------------------------------------------------------

function usage() { grep -E '^ *#\? *' $0 | cut -f 2- -d '?' ; exit; }

Makes it simple to extract header:

file       filename.sh
brief      Brief description
version    2024-07-05T22:40:33

and usage separately from the same header.

 $0 [OPTIONS]

 -?, -h, --help      Display this help and exit

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.