@@ -1086,6 +1086,16 @@ prop_checkSingleQuotedVariables22 = verifyNot checkSingleQuotedVariables "jq '$_
10861086prop_checkSingleQuotedVariables23 = verifyNot checkSingleQuotedVariables " command jq '$__loc__'"
10871087prop_checkSingleQuotedVariables24 = verifyNot checkSingleQuotedVariables " exec jq '$__loc__'"
10881088prop_checkSingleQuotedVariables25 = verifyNot checkSingleQuotedVariables " exec -c -a foo jq '$__loc__'"
1089+ prop_checkSingleQuotedVariables26 = verifyNot checkSingleQuotedVariables " gojq '$__loc__'"
1090+ prop_checkSingleQuotedVariables27 = verifyNot checkSingleQuotedVariables " dash -c 'echo $1'"
1091+ prop_checkSingleQuotedVariables28 = verifyNot checkSingleQuotedVariables " script -qec 'var=txt; echo \" $var\" ' /dev/null"
1092+ prop_checkSingleQuotedVariables29 = verifyNot checkSingleQuotedVariables " printf 'eval \" $(pyenv init - %s)\" ' \" $shell\" "
1093+ prop_checkSingleQuotedVariables30 = verifyNot checkSingleQuotedVariables " PS0='`history -a`'$PS0"
1094+ prop_checkSingleQuotedVariables31 = verifyNot checkSingleQuotedVariables " echo '\\ .$'\" $tld\" '\\ .$'"
1095+ prop_checkSingleQuotedVariables32 = verifyNot checkSingleQuotedVariables " echo '$foo'\" $bar\" "
1096+ prop_checkSingleQuotedVariables33 = verify checkSingleQuotedVariables " echo '$foo'"
1097+ prop_checkSingleQuotedVariables34 = verifyNot checkSingleQuotedVariables " find . -exec dash -c 'echo \" $1\" ' shell {} \\ ;"
1098+ prop_checkSingleQuotedVariables35 = verifyNot checkSingleQuotedVariables " run --separate-stderr bash -c 'echo \" $1\" '"
10891099
10901100
10911101checkSingleQuotedVariables params t@ (T_SingleQuoted id s) =
@@ -1110,6 +1120,7 @@ checkSingleQuotedVariables params t@(T_SingleQuoted id s) =
11101120 ," bash"
11111121 ," ksh"
11121122 ," zsh"
1123+ ," dash"
11131124 ," ssh"
11141125 ," eval"
11151126 ," xprop"
@@ -1122,17 +1133,21 @@ checkSingleQuotedVariables params t@(T_SingleQuoted id s) =
11221133 ," oc"
11231134 ," dpkg-query"
11241135 ," jq" -- could also check that user provides --arg
1136+ ," gojq" -- golang implementation of jq
11251137 ," rename"
11261138 ," rg"
11271139 ," unset"
1140+ ," printf"
1141+ ," script"
11281142 ," git filter-branch"
11291143 ," mumps -run %XCMD"
11301144 ," mumps -run LOOP%XCMD"
11311145 ]
11321146 || " awk" `isSuffixOf` commandName
11331147 || " perl" `isPrefixOf` commandName
1148+ || isConcatenatedWithExpansion
11341149
1135- commonlyQuoted = [" PS1" , " PS2" , " PS3" , " PS4" , " PROMPT_COMMAND" ]
1150+ commonlyQuoted = [" PS0 " , " PS1" , " PS2" , " PS3" , " PS4" , " PROMPT_COMMAND" ]
11361151 isOkAssignment t =
11371152 case t of
11381153 T_Assignment _ _ name _ _ -> name `elem` commonlyQuoted
@@ -1142,6 +1157,21 @@ checkSingleQuotedVariables params t@(T_SingleQuoted id s) =
11421157 re = mkRegex " \\ $[{(0-9a-zA-Z_]|`[^`]+`"
11431158 sedContra = mkRegex " \\ $[{dpsaic]($|[^a-zA-Z])"
11441159
1160+ -- When a single-quoted string is part of a word that also contains
1161+ -- double-quoted segments with expansions, the user clearly understands
1162+ -- quoting and is intentionally keeping parts in single quotes.
1163+ isConcatenatedWithExpansion =
1164+ case NE. tail $ getPath parents t of
1165+ (T_NormalWord _ parts): _ -> any hasExpansion parts
1166+ _ -> False
1167+ hasExpansion (T_DoubleQuoted _ parts) = any isExpansionToken parts
1168+ hasExpansion _ = False
1169+ isExpansionToken T_DollarBraced {} = True
1170+ isExpansionToken T_DollarExpansion {} = True
1171+ isExpansionToken T_DollarArithmetic {} = True
1172+ isExpansionToken T_Backticked {} = True
1173+ isExpansionToken _ = False
1174+
11451175 getFindCommand (T_SimpleCommand _ _ words ) =
11461176 let list = map getLiteralString words
11471177 cmd = dropWhile (\ x -> x `notElem` map Just [" -exec" , " -execdir" , " -ok" , " -okdir" ]) list
0 commit comments