3

The code below is an mwe based on a script mwe I've written where I specify flags in what I think is the usual way. But I'm seeing really wierd behavior. If I type mwe -e or mwe -n it thinks there are no arguments and returns no arg. If I type mwe -k or mwe -i it thinks argType is not "-" and returns breaking. If I comment out the four lines that end with a # the code works as expected. That suggests the problem is being caused by the while loop. Could somebody please explain what's happening?

#!/bin/bash
foo=0
argType=`echo "$1" | cut -c 1`
while [ 1 -gt 0 ] ;   #
    do   #
        if [ $# -eq 0 ] ; then
            echo no arg
            exit
        elif [ "$argType" != "-" ] ; then
            #No more flags
            echo breaking
            break  #
        elif [ "$1" = "-n"  ] ; then
            foo=1
            shift
        elif [ "$1" = "-e"  ] ; then
            foo=2
            shift
        elif [ "$1" = "-i"  ] ; then
            foo=3
            shift
        elif [ "$1" = "-k"  ] ; then
            foo=4
            shift
        fi
done  #
echo This is foo:  $foo
3
6

Third line should be

argType=$(printf "%s" "$1" | cut -c 1)

As mentioned in comments, echo interprets arguments such as -e as an option, so that -e would not be passed to cut. Worse, as a special case, end-of-options flag -- is not available to echo. Then, you need printf, which is usually better anyway.

Since you are in bash, you could adopt @steeldriver's suggestion and use argType=${1:0:1} (which means: For parameter 1, start at char 0 and get 1 char) instead of the pipeline. Notice that is not available in the POSIX shell, however.

Also prefer $() instead of backticks, since the latter harm readability, especially when nesting.

Finally, notice that you are shifting, so, even after that correction, if you try ./myscript -e -i, eventually [ $# -eq 0 ] will be true and the execution will be terminated by exit. Maybe that is intended, maybe not, but at the end of the day the last echo would not be triggered.

2
  • 1
    Also, the assignment to argType is before the loop, so it doesn't get updated as options are processed; it needs to be moved inside the loop to work right. Or, since this is bash, you could just use elif [[ "$1" != "-"* ]]; ... (note that this type of pattern matching requires a double-bracket conditional expression instead of just a single-bracket test). May 31 '20 at 22:33
  • 1
    If they're using a POSIX shell, they could use getopts... Also, there's the hilarious "${1%"${1#?}"}" that works in stead of ${1:0:1}
    – ilkkachu
    May 31 '20 at 22:33
2

From your question it is not clear what you want !

Anyhow it seems that you want the number corresponding to the last argument

#!/bin/bash
foo=0;

while [[ $# -gt 0 ]]; do
    case "${1}" in
        '-n')
            foo=1;
            shift
        ;;
        '-e')
            foo=2;
            shift
        ;;
        '-i')
            foo=3;
            shift
        ;;
        '-k')
            foo=4;
            shift
        ;;
        *)
            echo "Invalid flag";
            exit 1;
        ;;
    esac
done

echo "This is foo: $foo"

If instead you want a mechanism that treats and validates arguments before being processed, you can use something like

#!/bin/bash

inputf='';
outputf='';
text='';
format='';

while [[ $# -gt 0 ]];do
    case "${1}" in
        '-i')
            inputf="${2}";
            shift 2
        ;;
        '-o')
            outputf="${2}";
            shift 2
        ;;
        '-t')
            text="${2}";
            shift 2
        ;;
        '-f')
            format="${2}";
            shift 2
        ;;
    esac
done
2
  • first suggestion is great, thanks. would you mind adding an extra case for me, which would deal with unintended flags, e.g., if I typed -G it would return "flag not recognized" and exit
    – Leo Simon
    Jun 16 '20 at 4:21
  • for other cases we use glob star * that will catche anything other than valid flags
    – Yunus
    Jun 16 '20 at 11:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.