Parsing command line arguments in Bash

Facebooktwittergoogle_plusredditpinterestlinkedinmail
Parsing arguments is not that difficult. Not even in bash scripts.

Parsing arguments is not that difficult. Not even in bash scripts.

There’re many ways to parse arguments that were passed to a bash script. I’ll show two similar methods to parse the parameter schema -o /foo/ and --output=/foo/. The second example can also handle commands.

String manipulation just using Bash

If you’re not familiar with manipulation of string (like ${var#=*} or similar) keep on reading. We’ll select sub-strings from the arguments in the following scripts. The command to do so looks like this: ${<VARIABLE><SPLIT-CHARS><REGEX>}

The split chars define what the result is, which is always one single string. There’re four different ones:

# Removes the shortest match from the beginning:
$var="ab=cd=ef"
${var#*=}
The result is cd=ef, because ab= is the shortest match.
## Removes the longest match from the beginning:
$var="ab=cd=ef"
${var##*=}
The result is ef, because ab=cd= is the longest match.
% Removes the shortest match from the end:
$var="ab=cd=ef"
${var%=*} (attention, the star is now behind the equals 😉 )
The result is ab=cd, because =ef is the shortest match.
%% Removes the longest match from the end:
$var="ab=cd=ef"
${var%%=*}
The result is ab, because =cd=ef is the longest match.

 

We’ll use these operation to determine the value of a parameter. For --package=foo the result should be foo.

For more information on string manipulations, have a look at https://www.tldp.org/LDP/abs/html/string-manipulation.html.

The format of the arguments

I mostly follow the POSIX standard with the GNU extension for long arguments. That means that the following arguments are valid:

-h
--help
-p foo
--package=foo

I ignore things like -hv (for -h and -v) or -pfoo (as equivalent for -p foo) to keep it simple.

Simple example

A working bash script can be found here: https://gist.github.com/hauke96/2e8c8630906bc5253c84ed83751e045b

Many people use the while loop to iterate over the arguments. That results in having many shift statements to move to the next argument and I find it kind of unhandy. I’m also a fan of having an index I can work with and therefore I use the for loop. When an argument is separated by a space (e.g. -p foo) from its value, $i needs to be incremented manually.

Example with commands

Commands are basically subroutines of the actual program and might have their own arguments. The command apt-get install ... for example takes multiple packages as arguments, whereas apt-get update doesn’t allow any arguments.

A working bash script can be found here: https://gist.github.com/hauke96/d069bcf32ec35c66412e9ee50b0295a8

The format I use is bash command.sh <COMMAND> <ARGUMENTS>

First the command (which is <COMMAND> in the format above) will be parsed using arg=${@:1:1}. The only allowed command in the example is install.

Because each command can have own arguments, those are parsed in the parse_install_args. This function then looks like the routine in the simple example.

Alternatives

As I said before, many people are using the while loop. Other implementations can be found for example on Stackoverflow.

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Leave a Comment

Your email address will not be published.