For the following code, I'm getting SC2089 "Quotes/backslashes will be treated literally, use an array"
# Quotes/backslashes will be treated literally, use an array
CMD_AVAIL_MSG='%s is required for this script but the "%s" command is missing. Exiting...'
if [ -z "$(which valet)" ]; then
printf -v err $CMD_AVAIL_MSG "Laravel Valet" "valet";
echo $err; # there's other stuff I do here, but using echo for conciseness
exit 1;
fi
However, converting this to an array gives me shellcheck warning SC2059 "Don't use variables in the printf format string, use '...%s...' $foo"
CMD_AVAIL_MSG=("%s" 'is required for this script but the "' '%s' '" command is missing. Exiting...')
if [ -z "$(which valet)" ]; then
# Don't use variables in the printf format string, use '...%s...' "$foo"
printf -v err "${CMD_AVAIL_MSG[@]}" "Laravel Valet" "valet";
echo $err; # there's other stuff I do here, but using echo for conciseness
exit 1;
fi
How do I resolve both of these warnings?
Warning SC2059 is intended to prevent people from passing data in the format-string position. You aren't doing that (your "data" is in fact a format string), so it isn't intended for you and can be safely disabled.
On the other hand, you are still misusing printf: Because each invocation of printf
accepts only a single format string, CMD_AVAIL_MSG
should be a regular string, not an array. (It also should be lowercase; all-caps names are reserved by POSIX-specified convention for variables that reflect or modify behavior of the shell or other POSIX-specified tools).
cmd_avail_msg='"%s" is required for this script but the "%s" command is missing. Exiting...'
if ! command -v valet >/dev/null 2>&1; then
# shellcheck disable=SC2059
printf -v err "$cmd_avail_msg" 'Laravel Valet' valet
echo "$err" >&2
exit 1;
fi
Note the use of if ! command -v valet >/dev/null 2>&1
instead of if [ -z "$(which valet)" ]
. This is both more efficient and more portable: which
is a separate executable being run as a subprocess, whereas command -v
is a POSIX-specified command internal to the shell itself.
The above being said, this looks like a place where you can, and perhaps should, use a function instead of a variable with a format string -- that way you can reuse the entire code block, not just the single message.
check_for_cmd() {
local cmd=$1 name=$2 err
command -v "$cmd" >/dev/null 2>&1 && return 0
printf -v err \
'"%s" is required for this script but the "%s" command is missing. Exiting...' \
"$name" "$cmd"
# do other stuff here
echo "$err" >&2
exit 1
}
check_for_cmd valet "Laravel Valet"
check_for_cmd other "Something Else"