Search code examples
bashglobshellcheck

Cannot figure out how to fix shellcheck complaint that I should not use a glob as a command when starting one script from another


Example script:

#!/bin/bash

printf '1\n1\n1\n1\n' | ./script2*.sh >/dev/null 2>/dev/null

Shellcheck returns the following:

In script1.sh line 3:
printf '1\n1\n1\n1\n' | ./script2*.sh >/dev/null 2>/dev/null
                        ^-- SC2211: This is a glob used as a command name. Was it supposed to be in ${..}, array, or is it missing quoting?

According to https://github.com/koalaman/shellcheck/wiki/SC2211, there should be no exceptions to this rule.

Specifically, it suggests "If you want to specify a command name via glob, e.g. to not hard code version in ./myprogram-*/foo, expand to array or parameters first to allow handling the cases of 0 or 2+ matches."

The reason I'm using the glob in the first place is that I append or change the date to any script that I have just created or changed. Interestingly enough, when I use "bash script2*.sh" instead of "./script2*.sh" the complaint goes away.

Have I fixed the problem or I am tricking shellcheck into ignoring a problem that should not be ignored? If I am using bad bash syntax, how might I execute another script that needs to be referenced to using a glob the proper way?


Solution

  • The problem with this is that ./script2*.sh may end up running

    ./script2-20171225.sh ./script2-20180226.sh ./script2-copy.sh
    

    which is a strange and probably unintentional thing to do, especially if the script is confused by such arguments, or if you wanted your most up-to-date file to be used. Your "fix" has the same fundamental problem.

    The suggestion you mention would take the form:

    array=(./script2*.sh)
    [ "${#array[@]}" -ne 1 ] && { echo "Multiple matches" >&2; exit 1; }
    "${array[0]}"
    

    and guard against this problem.

    Since you appear to assume that you'll only ever have exactly one matching file to be invoked without parameters, you can turn this into a function:

    runByGlob() {
      if (( $# != 1 ))
      then
        echo "Expected exactly 1 match but found $#: $*" >&2
        exit 1
      elif command -v "$1" > /dev/null 2>&1
      then
        "$1"
      else
        echo "Glob is not a valid command: $*" >&2
        exit 1
      fi
    }
    
    whatever | runByGlob ./script2*.sh
    

    Now if you ever have zero or multiple matching files, it will abort with an error instead of potentially running the wrong file with strange arguments.