Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write a bash script that takes parameters in any given order?

I want to know what principles I should use in order to write a bash script that takes its parameters in any given order. For example:

  • Let's name my script: script.sh
  • And let's say that I want it to take either no or at least two parameters.
  • Now suppose that one standard parameter is the -f which specifies that the very next parameter is the name of the file I should process.
  • Once more suppose that the given file is named: input.dat
  • And finally (for the sake of the example), suppose that the last two parameters I can add are named: -print and -delete

What I am asking here is:

Is there a specific way (or even programming technique) I can use so that the parameters can be passed in any given order (besides the fact that the filename should always follow the -f parameter?

Here are some invoking examples:

  1. ./script.sh -f input.dat -print
  2. ./script.sh -print -f input.dat

The above two executions should produce the very same example!

When answering please do keep in mind that the real problem has many more parameters and different outcomes!

like image 987
Christos Maris Avatar asked Oct 26 '25 14:10

Christos Maris


2 Answers

Here's the script I wrote to achieve this:

#!/bin/bash

# The code below was written to replace the -print and -delete options for
# -p and -d respectively, because getopts can't handle long args, I suggest
# you only use arguments of single letters to make your code more simple, but if 
# you can't avoid it then this is a workaround

for ARGS in "$@"; do
shift
        case "$ARGS" in
                "-print") set -- "$@" "-p" ;;
                "-delete") set -- "$@" "-d" ;;
                *) set -- "$@" "$ARGS"
        esac
done
# getopts works like this: you put all your arguments between single quotes
# if you put a ':' character after the argument letter (just like I did with
# the 'f' letter in the example below), it means this argument NEEDS an extra
# parameter. If you just use letters without the ':' it means it doesn't need
# anything but the argument itself (it's what I did for the '-p' and '-d' options)

while getopts 'f:pd' flag; do
        case "${flag}" in
                f) FILE=${OPTARG} ;;
                p) COMMAND="print" ;;
                d) COMMAND="delete" ;;
        esac
done

echo "$COMMAND $FILE"

And below examples of it running:

$ ./script.sh -f filename -print
print filename
$ ./script.sh -print -f filename
print filename
$ ./script.sh -f filename -delete
delete filename
$ ./script.sh -delete -f filename
delete filename
like image 147
AFAbyss Avatar answered Oct 28 '25 05:10

AFAbyss


The previous solution is a good starting point, I played around with it for being able to accept multiple arguments to a flag, and I think this is a bit better style (less unused variables too):

#!/bin/bash
while [ $# -gt 0 ]; do
    case "$1" in
        --file|-f) filename=$2 ; shift;;
        --print|-p) printCommand ;;
        --delete|-d) deleteCommand ;;
        *) break
    esac
shift
done

Also note shift can take number of moves as an argument, this helps to keep it tidy. eg:

--two-files) filename1=$2; filename2=$3; shift 2;;
like image 27
FuzzyJulz Avatar answered Oct 28 '25 04:10

FuzzyJulz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!