Suggest removing null checks in parameter expansions

${parameter-} expands to the empty string if parameter is unset.
${parameter:-} is a more verbose way of saying the same thing, because
it expands to the empty string if parameter is unset or empty, and if
parameter is empty, it merely replaces one empty with another.

Similarly, ${parameter=} assigns the empty string to parameter if
parameter is unset, which is equivalent to what ${parameter:=} does,
since assigning the empty string to a parameter already holding the
empty string is a no-op.

(Of course, when the replacement to the right of the - or = is
non-empty, there is a meaningful difference between the versions with
and without the null-check colon.)
This commit is contained in:
Ryan Hendrickson 2025-07-25 15:32:02 -04:00
commit d58ce336e6
2 changed files with 15 additions and 6 deletions

View file

@ -5,6 +5,7 @@
- SC2330: Warn about unsupported glob matches with [[ .. ]] in BusyBox. - SC2330: Warn about unsupported glob matches with [[ .. ]] in BusyBox.
- SC2331: Suggest using standard -e instead of unary -a in tests. - SC2331: Suggest using standard -e instead of unary -a in tests.
- SC2332: Warn about `[ ! -o opt ]` being unconditionally true in Bash. - SC2332: Warn about `[ ! -o opt ]` being unconditionally true in Bash.
- SC2335: In parameter expansions, suggest replacing `:-`/`:=` with `-`/`=` when the substitution is empty.
- SC3062: Warn about bashism `[ -o opt ]`. - SC3062: Warn about bashism `[ -o opt ]`.
- Precompiled binaries for Linux riscv64 (linux.riscv64) - Precompiled binaries for Linux riscv64 (linux.riscv64)
### Changed ### Changed

View file

@ -1808,13 +1808,17 @@ prop_checkBadParameterSubstitution8 = verify checkBadParameterSubstitution "${$(
prop_checkBadParameterSubstitution9 = verifyNot checkBadParameterSubstitution "$# ${#} $! ${!} ${!#} ${#!}" prop_checkBadParameterSubstitution9 = verifyNot checkBadParameterSubstitution "$# ${#} $! ${!} ${!#} ${#!}"
prop_checkBadParameterSubstitution10 = verify checkBadParameterSubstitution "${'foo'}" prop_checkBadParameterSubstitution10 = verify checkBadParameterSubstitution "${'foo'}"
prop_checkBadParameterSubstitution11 = verify checkBadParameterSubstitution "${${x%.*}##*/}" prop_checkBadParameterSubstitution11 = verify checkBadParameterSubstitution "${${x%.*}##*/}"
prop_checkBadParameterSubstitution12 = verify checkBadParameterSubstitution "${var:-}"
prop_checkBadParameterSubstitution13 = verifyNot checkBadParameterSubstitution "${var:-x} ${var-} ${var:-$(cmd)}"
prop_checkBadParameterSubstitution14 = verify checkBadParameterSubstitution "${var:=}"
prop_checkBadParameterSubstitution15 = verifyNot checkBadParameterSubstitution "${var:=x} ${var=} ${var:=$(cmd)}"
checkBadParameterSubstitution _ t = checkBadParameterSubstitution params t =
case t of case t of
(T_DollarBraced i _ (T_NormalWord _ contents@(first:_))) -> (T_DollarBraced i _ (T_NormalWord _ contents@(first:more))) ->
if isIndirection contents if isIndirection contents
then err i 2082 "To expand via indirection, use arrays, ${!name} or (for sh only) eval." then err i 2082 "To expand via indirection, use arrays, ${!name} or (for sh only) eval."
else checkFirst first else checkFirst first more
_ -> return () _ -> return ()
where where
@ -1833,11 +1837,15 @@ checkBadParameterSubstitution _ t =
else Just False else Just False
_ -> Just False _ -> Just False
checkFirst t = checkFirst t more =
case t of case t of
T_Literal id (c:_) -> T_Literal id s@(c:_) ->
if isVariableChar c || isSpecialVariableChar c if isVariableChar c || isSpecialVariableChar c
then return () then case reverse s of
x : ':' : _ | [] <- more, x `elem` "-=" -> -- i.e., s ends with ":-" or ":="
styleWithFix id 2335 ("Checking for null is unnecessary when replacing with null. Remove the colon.") $
fixWith [ replaceEnd id params 2 [x] ]
_ -> return ()
else err id 2296 $ "Parameter expansions can't start with " ++ e4m [c] ++ ". Double check syntax." else err id 2296 $ "Parameter expansions can't start with " ++ e4m [c] ++ ". Double check syntax."
T_ParamSubSpecialChar {} -> return () T_ParamSubSpecialChar {} -> return ()