How to run a specified codeblock with getopts when no options or arguments are supplied?

5,132

You can use any of the following to run commands when $1 is empty:

[[ ! $1 ]] && { COMMANDS; }
[[ $1 ]] || { COMMANDS; }
[[ -z $1 ]] && { COMMANDS; }
[[ -n $1 ]] || { COMMANDS; }

Also, you don't need to quote the expansion in this particular example, as no word splitting is performed.

If you're wanting to check if there are arguments, though, you'd be better to use (( $# )).

If I've understood your intentions, here is how your code could be written with getopts:

#!/bin/bash

(( $# )) || printf '%s\n' 'No arguments'

while getopts ':n:h' opt; do
    case "$opt" in
        n)
            [[ $OPTARG ]] && printf '%s\n' "Commands were run, option $OPTARG, so let's do what that says."
            [[ ! $OPTARG ]] && printf '%s\n' "Commands were run, there was no option, so let's run some stuff."
            ;;
        h) printf '%s\n' 'Help printed' ;;
        *) printf '%s\n' "I don't know what that argument is!" ;;
    esac
done
Share:
5,132

Related videos on Youtube

MaQleod
Author by

MaQleod

I'm a Software Quality Principal Engineer that specializes in Networking and hardware (with a strong emphasis on Unix/Linux systems). My background is in Telecom and Network troubleshooting. I am proficient in both Ethernet and Infiniband standards. I code primarily with Python, Autoit, C and and SQL in my spare time, but I like to occasionally tinker in other languages. My degree is in Classical Numismatics and Archaeology. I also keep a blog on investing. profile for MaQleod on Stack Exchange, a network of free, community-driven Q&A sites http://stackexchange.com/users/flair/343e8ac1ebe84dacb26151af03317dcd.png

Updated on September 18, 2022

Comments

  • MaQleod
    MaQleod almost 2 years

    So I am writing a script that mixes options with arguments with options that don't. From research I have found that getopts is the best way to do this, and so far it has been simple to figure out and setup. The problem I am having is figuring out how to set this up so that if no options or arguments are supplied, for it to run a separate set of commands. This is what I have:

    while getopts ":n:h" opt; do
      case $opt in
        n)
          CODEBLOCK >&2
          ;;
        h)
          echo "script [-h - help] [-n <node> - runs commands on specified node]" >&2
          exit 1
          ;;
        \?)
          echo "Invalid option: -$OPTARG" >&2
          exit 1
          ;;
        :)
          echo "Option -$OPTARG requires an argument." >&2
          exit 1
          ;;
      esac
    done
    

    I have tried adding something like this to the top of the code to catch no arguments, but it then runs the same code even when options and arguments are supplied (something is probably wrong in my syntax here):

    [[ -n "$1" ]] || {
    CODEBLOCK1
    }
    
    while getopts ":n:h" opt; do
      case $opt in
        n)
          CODEBLOCK2 >&2
          ;;
        h)
          echo "script [-h - help] [-n <node> - runs commands on specified node]" >&2
          exit 1
          ;;
        \?)
          echo "Invalid option: -$OPTARG" >&2
          exit 1
          ;;
        :)
          echo "Option -$OPTARG requires an argument." >&2
          exit 1
          ;;
      esac
    done
    

    The man page for getopts was sparse and I have found relatively few examples on searches that provide any insight into getopts, let alone all the various features of it.

  • MaQleod
    MaQleod almost 13 years
    Using -n or -z has the same effect. Whether I type ./script or ./script -n 3, the same codeblock is executed and everything in the getopts loop is ignored.
  • clerksx
    clerksx almost 13 years
    That's simply not possible -- -z will evaluate to true if $1 is empty. What is the smallest code sample that demonstrates the issue that you are having directly?
  • MaQleod
    MaQleod almost 13 years
    I did paste it wrong, in the script I'm running I have it set differently, I corrected that in the question, but I am not having problems with the getopts loop. I updated with an example, and it is probably something in my syntax that is keeping it from working properly. I tried all the different options you posted in your answer and all failed to work properly.
  • clerksx
    clerksx almost 13 years
    The above code should show you how to implement checking for situations where there are either a.) no arguments, or b.) arguments without an option.
  • MaQleod
    MaQleod almost 13 years
    No matter how I do it, whether an option is provided or not, the code runs CODEBLOCK1. The only variance is with the first option [[ ! $1 ]] && { COMMANDS; } , it runs CODEBLOCK2 as expected, but will not ever run CODEBLOCK1, it produces an error: [[: not found. I even tested it with (( $# )) || and had the same as the majority of the others.
  • clerksx
    clerksx almost 13 years
    [[: not found indicates that you are not running bash, or you are running it as #!/bin/sh. sh is the POSIX or Bourne shell, not bash. Even if sh is a symlink to bash, running a script under sh (either by typing sh myscript or putting #!/bin/sh at the top) disables many bash features. You can either use [ instead (make sure to quote any expansions), or run bash in non-POSIX mode.
  • MaQleod
    MaQleod almost 13 years
    it is zsh, but I can't change that, I can't change anything with the system, only the script. I am running it with #!/bin/sh. Even if I use a [ and quote the expansion I have the same results.
  • MaQleod
    MaQleod almost 13 years
    Ok, so single brackets did the trick.
  • clerksx
    clerksx almost 13 years
    If you are using zsh, please do not push bash in your tags in future. They are not the same.