0

I wrote a simple bash script for some USB webcam image settings and restarting of the webcamd service.

At this moment, when someone uses the -t flag, they can use only "n" or "d", if they use something else, it throws an error. However the same error happens if they use -t without any parameter.

Is there a way to handle these two separately?

Also, is there a way to use "case" statement for multiple variables in some other way than what I used?

I am thinking something like what I can do in VBA:

Select Case True
    Case a = 1 and b = 2
        *something something*
    Case a = 2 and b = 1
        *something something*
End Select

Thank you

#!/bin/bash

RESTART="The camera was restarted."
RESTARTDAY="The camera was restarted and controls were set for daytime."
RESTARTNIGHT="The camera was restarted and controls were set for nighttime."
DAY="The camera controls were set for daytime."
NIGHT="The camera control were set for nighttime."
REST=false
TIME=false

unstuck_image(){

v4l2-ctl -c brightness=10
v4l2-ctl -c contrast=10
v4l2-ctl -c gamma=10
v4l2-ctl -c saturation=10
v4l2-ctl -c sharpness=10

}

set_night(){

v4l2-ctl -c gain_automatic=0
v4l2-ctl -c brightness=75
v4l2-ctl -c contrast=75
v4l2-ctl -c gamma=20
v4l2-ctl -c saturation=15
v4l2-ctl -c sharpness=90

}

set_day(){

v4l2-ctl -c gain_automatic=0
v4l2-ctl -c brightness=50
v4l2-ctl -c contrast=50
v4l2-ctl -c gamma=20
v4l2-ctl -c saturation=15
v4l2-ctl -c sharpness=90

}

restart_camera(){

sudo service webcamd restart

}

while getopts :rt: option
do
    case "${option}" in
        r)
            REST=true
            #echo "Restart"
            ;;
        t)
            TIMEOFDAY=${OPTARG}
            TIME=true
            case "$TIMEOFDAY" in
                n | d)
                    #echo "$TIMEOFDAY"
                    ;;
                *)
                    echo "Invalid argument for -t, use only 'd' or 'n'"
                    exit 0
                    ;;
            esac
            ;;
        *)
            echo "Argument -${OPTARG} not found."
            echo "Use only -r and -t."
            exit 0
            ;;
    esac
done

RESTTIME="$REST""$TIME"
#echo "$RESTTIME"
#echo "$RESTART"

case "$RESTTIME" in
    "truefalse") #Only restart webcamd
        restart_camera
        MESSAGE="$RESTART"
        ;;
    "truetrue") #Restart webcamd and set camera controls
        case "$TIMEOFDAY" in
            d)
                restart_camera
                unstuck_image
                set_day
                MESSAGE="$RESTARTDAY"
                ;;
            n)
                restart_camera
                unstuck_image
                set_night
                MESSAGE="$RESTARTNIGHT"
                ;;
        esac
        ;;
    "falsetrue") #Only set the camera controls
        case "$TIMEOFDAY" in
            d)
                unstuck_image
                set_day
                MESSAGE="$DAY"
                ;;
            n)
                unstuck_image
                set_night
                MESSAGE="$NIGHT"
                ;;
        esac
        ;;
esac

echo "$MESSAGE"

EDIT:

Apart from spuck's answer, I did some digging on my own and found it it can also be done this way:

while getopts :rt: option
do
    case "${option}" in
        r)
            REST=true
            #echo "Restart"
            ;;
        t)
            TIMEOFDAY="${OPTARG}"
            TIME=true
            case "${TIMEOFDAY}" in
                n | d)
                    #echo "$TIMEOFDAY"
                    ;;
                "")
                    echo "-t argument requires an option. Use 'd' or 'n'."
                    exit 2
                    ;;
                *)
                    echo "Invalid argument for -t. Use only 'd' or 'n'"
                    exit 0
                    ;;
            esac
            ;;
        \?)
            echo "Argument -"${OPTARG}" not found. Use only -r and -t."
            exit 0
            ;;
        :)
            echo "Invalid option: -"${OPTARG}" requires an argument"
            exit 2
            ;;
    esac
done

where :) handles when a flag's argument is not optional, but it is missing.

4
  • What do you want it to do if "-t" is given with no option? – spuck Nov 2 '20 at 20:13
  • Probably echo something about missing option – GohanCZ Nov 2 '20 at 20:28
  • A missing option to -t should already be handled by the *) switch in the inner case statement. Do you want it to print something different for a blank option to -t as opposed to an option other than 'd' or 'n'? – spuck Nov 2 '20 at 21:20
  • Exactly. I want to echo different string for missing option and another one for invalid option. – GohanCZ Nov 2 '20 at 21:22
0

Your use of getopts :rt: tells the shell that you are requiring an argument to option "t".

From the getopts man page:

[...] if a character is followed by a colon, the option is expected to have an argument, which should be separated from it by white space [...] When an option requires an argument, getopts places that argument into the variable OPTARG

If you want to make the argument to -t optional, you need to remove the colon and handle the next argument by hand:

while getopts :rt option
do
    case "${option}" in
        r)
            REST=true
            #echo "Restart"
            ;;
        t)
            TIMEOFDAY=${!OPTIND}
            TIME=true
            case "$TIMEOFDAY" in
                n | d)
                    echo "$TIMEOFDAY"
                    ;;
                "")
                    echo "-t argument requires an option."
                    exit 2
                    ;;
                *)
                    echo "Invalid argument for -t, use only 'd' or 'n'"
                    exit 0
                    ;;
            esac
            ;;
            *)
               echo "Argument -${OPTARG} not found."
               echo "Use only -r and -t."
               exit 0
               ;;
    esac
done

There are two changes from your code:

  1. Changing the "optstring" from :rt: to :rt tells getopts that the "t" option does not require an argument to follow.
  2. Changed the line TIMEOFDAY=${OPTARG} to TIMEOFDAY=${!OPTIND}.

Again from the man page:

Each time it is invoked, the getopts utility shall place the value of the next option in the shell variable specified by the name operand and the index of the next argument to be processed in the shell variable OPTIND.

So when processing the "t" option, the OPTIND variable will have the index number of the next option. The syntax ${!variable} indirectly references the value of variable.

I've re-created it in a sandbox and added another line to echo the value of OPTIND to help explain it here: Try it online!

5
  • Im not following. I dont need to add x and p. I only need n or d. Why should I add p and x ? I also think your syntax is a bit off, -tx is not the same as -t x – GohanCZ Nov 2 '20 at 20:30
  • Unfortunately the error is the same as with *), so no change. – GohanCZ Nov 2 '20 at 21:54
  • Now it works! Thank you a lot. I ve noticed that you removed the colon after t and also changed TIMEOFDAY from ${OPTARG} to ${!OPTIND}. Can i please ask what these changes did ? Thank you – GohanCZ Nov 3 '20 at 11:27
  • @GohanCZ, I've update the answer a final time. Hope it helps. – spuck Nov 3 '20 at 16:09
  • It does, thank you! I also did some reading online, and find out how it should be "properly" done I believe. – GohanCZ Nov 3 '20 at 20:26

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.