Search code examples
bashcommand-line-argumentsgetopts

getopts optional and no optional arguments


Having problems with my getopts function to work properly. What should happened is that if no agruments are given, then everything is defaulted. I have four options as follows:

-b that needs a value of either one of the two 2048 or 4096 otherwise usage.

-c needs a value of path otherwise usage.

-p needs a value of path otherwise usage

-h which does need a value which is ignored even it does.

But if I leave off a option, it won't allow me to continue. So I need to be able to put 0 to 4.

msg=""
nginx_ssl_conf=/etc/nginx/nginx-ssl.conf
BIT_SIZE=2048 
isHardened=false
hardened_ciphers="'ECDH+AESGCM256:DH+AESGCM256:ECDH+AES256:SH+AES256:RSA+AESGCM256:RSA+AES256:!aNULL:!MD5:!kEDH';"
DHEC_path=$STORAGE_ROOT/ssl/dhparam.pem


# Usage info
usage() {
cat << EOF
Usage: ${0##*/} [-h] [-p DIR_DHEC_KEY] [-b BIT_SIZE]  [-c DIR_NGINX_SSL]...
This script generates and enables DHEC for Nginx.  Defaulted to 2048 key.
Hardened mode will generate 4096 key and the following cipher suites:
'ECDH+AESGCM256:DH+AESGCM256:ECDH+AES256:SH+AES256:RSA+AESGCM256:RSA+AES256:!aNULL:!MD5:!kEDH'

    -h          Enable hardened ciphers and 4096 bit key.
    -p          Specify dir to generate the DHEC key.
    -c          Specify dir nginx ssl conf is. 
    -b          Specify the bit size to generate.
EOF
exit 1
}  


while getopts "::b:h:::p::c" opt ; do
    case "${opt}" in
        b)
            BIT_SIZE=${OPTARG}
            if [ -z "${b}"]; then
               usage
            fi
            ;;
        h)
            isHardened=true
            BIT_SIZE=4096 
            ;;
    p)
            DHEC_path=${OPTARG}
            ;;
        c)
            nginx_ssl_conf=${OPTARG}
            ;;

        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

Solution

  • Change what you have with this:

    while getopts "hb:c:p:" opt ; do
        case "${opt}" in
            b)
                BIT_SIZE=${OPTARG}
                if [ -z "${BIT_SIZE}" ]; then
                   usage
                fi
                ;;
    

    Note I changed the getopts argument, fixed the ${b} invalid variable, and added the requisite space before the ] in the b) case.

    That should get you closer. I'm not 100% I follow your use case, and what I do understand I think I might approach differently. For example, as you have it written now, -b 2048 -h produces a different BIT_SIZE than you and the user might expect. (Compare it with -h -b 2048 to see what I mean: argument order shouldn't matter with flags, typically.)

    Edit
    To use the -b bit value if given, otherwise use the -h bit value if given, otherwise to use a default, the relevant changes I'd make are:

    DEFAULT_BIT_SIZE=2048
    isHardened="false"
    
    while getopts "hb:c:p:" opt ; do
        case "${opt}" in
            b)
                BIT_SIZE=${OPTARG}
                if [ -z "${BIT_SIZE}" ]; then
                   usage
                fi
                ;;
            h)
                isHardened="true"
                ;;
        esac
    done
    shift $((OPTIND-1))
    
    if [ -z "${BIT_SIZE}" -a "true" == "${isHardened}" ]; then
        BIT_SIZE=4096
    elif [ -z "${BIT_SIZE}" ]; then
        BIT_SIZE=$DEFAULT_BIT_SIZE
    fi