Bash: How to use while shift; do..case $1 in
I'm working on a bash script and i need to implement "options". How can i do that with bash?
my goal is tu run script the following way:/myscript.sh -d "/var/log/" -c "test"
what i've tried:
while shift; do case $1 in -d) shift&&DIR="$1"||die ;; -c) shift&&COMMAND="$1"||die ;; esac
done
echo "$DIR"
echo "$COMMAND" 2 4 Answers
To expand @choroba's answer, here's an example of how to use getopts:
# parse the flag options (and their arguments)
while getopts c:d: OPT; do case "$OPT" in d) DIR="$OPTARG" ;; c) COMMAND="$OPTARG" ;; [?]) # got invalid option echo "Usage: $0 [-d directory] [-c command]" >&2 exit 1 ;; esac
done
# get rid of the just-finished flag arguments
shift $(($OPTIND-1))Note that after shifting off the flag arguments, any "regular" arguments will remain. So at that point you could either deal with them (e.g. ... for arg in "$@"; do ...) or if your script doesn't take them just gripe if you get any (if [ $# -gt 0 ]; then echo "Usage ...).
Your mistake is that you're shifting at the top of the loop, tossing the first argument before you've examined it. This is what I think you probably meant:
#!/bin/bash
while (( "$#" )); do case $1 in -d) shift&&DIR="$1"||die ;; -c) shift&&COMMAND="$1"||die ;; esac shift
done
echo "$DIR"
echo "$COMMAND" 3 As choroba already said, getopts is a better approach.
In your case, you could use:
getopts c:d: d || die
DIR=$OPTARG
getopts c:d: c || die
COMMAND=$OPTARGto achieve what you're trying to do with the while loop.
The string c:d: specifies the possible switches. The colon means that the switch requires an argument.
The problem with your approach is that you call shift before analyzing the first argument, discarding it in the process.
To fix this, change the while loop to the following:
while true; do case $1 in -d) shift&&DIR="$1"||die ;; -c) shift&&COMMAND="$1"||die ;; esac shift || break
done The usual approach is to use getopts.