# Scripting with Parameters

# Multiple Parameter Parsing

To parse lots of parameters, the prefered way of doing this is using a while loop, a case statement, and shift.

shift is used to pop the first parameter in the series, making what used to be $2, now be $1. This is useful for processing arguments one at a time.

#!/bin/bash # Load the user defined parameters while [[ $# > 0 ]] do case "$1" in -a|--valueA) valA="$2" shift ;; -b|--valueB) valB="$2" shift ;; --help|*) echo "Usage:" echo " --valueA \"value\"" echo " --valueB \"value\"" echo " --help" exit 1 ;; esac shift done echo "A: $valA" echo "B: $valB" 

Inputs and Outputs

$ ./multipleParams.sh --help Usage: --valueA "value" --valueB "value" --help $ ./multipleParams.sh A: B: $ ./multipleParams.sh --valueB 2 A: B: 2 $ ./multipleParams.sh --valueB 2 --valueA "hello world" A: hello world B: 2 

# Accessing Parameters

When executing a Bash script, parameters passed into the script are named in accordance to their position: $1 is the name of the first parameter, $2 is the name of the second parameter, and so on.

A missing parameter simply evaluates to an empty string. Checking for the existence of a parameter can be done as follows:

if [ -z "$1" ]; then echo "No argument supplied" fi 

# Getting all the parameters

$@ and $* are ways of interacting with all the script parameters. Referencing the Bash man page (opens new window), we see that:

  • $*: Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable.
  • $@: Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word.

# Getting the number of parameters

$# gets the number of parameters passed into a script. A typical use case would be to check if the appropriate number of arguments are passed:

if [ $# -eq 0 ]; then echo "No arguments supplied" fi 

# Example 1

Loop through all arguments and check if they are files:

for item in "$@" do if [[ -f $item ]]; then echo "$item is a file" fi done 

# Example 2

Loop through all arguments and check if they are files:

for (( i = 1; i <= $#; ++ i )) do item=${@:$i:1} if [[ -f $item ]]; then echo "$item is a file" fi done 

# Argument parsing using a for loop

A simple example which provides the options:

Opt Alt. Opt Details
-h --help Show help
-v --version Show version info
-dr path --doc-root path An option which takes a secondary parameter (a path)
-i --install A boolean option (true/false)
-* -- Invalid option
#!/bin/bash dr='' install=false skip=false for op in "$@";do if $skip;then skip=false;continue;fi case "$op" in -v|--version) echo "$ver_info" shift exit 0 ;; -h|--help) echo "$help" shift exit 0 ;; -dr|--doc-root) shift if [[ "$1" != "" ]]; then dr="${1/%\//}" shift skip=true else echo "E: Arg missing for -dr option" exit 1 fi ;; -i|--install) install=true shift ;; -*) echo "E: Invalid option: $1" shift exit 1 ;; esac done 

# Wrapper script

Wrapper script is a script that wraps another script or command to provide extra functionalities or just to make something less tedious.

For example, the actual egrep in new GNU/Linux system is being replaced by a wrapper script named egrep. This is how it looks:

#!/bin/sh exec grep -E "$@" 

So, when you run egrep in such systems, you are actually running grep -E with all the arguments forwarded.

In general case, if you want to run an example script/command exmp with another script mexmp then the wrapper mexmp script will look like:

#!/bin/sh exmp "$@" # Add other options before "$@" # or #full/path/to/exmp "$@" 

# Split string into an array in Bash

Let's say we have a String parameter and we want to split it by comma

my_param="foo,bar,bash" 

To split this string by comma we can use;

IFS=',' read -r -a array <<< "$my_param" 

Here, IFS is a special variable called Internal field separator (opens new window) which defines the character or characters used to separate a pattern into tokens for some operations.

To access an individual element:

echo "${array[0]}" 

To iterate over the elements:

for element in "${array[@]}" do echo "$element" done 

To get both the index and the value:

for index in "${!array[@]}" do echo "$index ${array[index]}" done 

# Remarks

  • shift shifts the positional parameters to the left so that $2 becomes $1, $3 becomes $2 and so forth.
  • "$@" is an array of all the positional parameters passed to the script/function.
  • "$*" is an string composed of all the positional parameters passed to the script/function.