Skip to content

Commit c41f3a4

Browse files
committed
Warn about [ ! -o opt ] (and -a) being unconditionally true (fixes #3174)
1 parent 574c6d1 commit c41f3a4

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
- SC2329: Warn when (non-escaping) functions are never invoked.
55
- SC2330: Warn about unsupported glob matches with [[ .. ]] in BusyBox.
66
- SC2331: Suggest using standard -e instead of unary -a in tests.
7+
- SC2332: Warn about `[ ! -o opt ]` being unconditionally true in Bash.
8+
- SC3062: Warn about bashism `[ -o opt ]`.
79
- Precompiled binaries for Linux riscv64 (linux.riscv64)
810
### Changed
911
- SC2002 about Useless Use Of Cat is now disabled by default. It can be

src/ShellCheck/Checks/ShellSupport.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ checks = [
6363
,checkPS1Assignments
6464
,checkMultipleBangs
6565
,checkBangAfterPipe
66+
,checkNegatedUnaryOps
6667
]
6768

6869
testChecker (ForShell _ t) =
@@ -218,6 +219,7 @@ prop_checkBashisms124 = verify checkBashisms "#!/bin/dash\ntype -p test"
218219
prop_checkBashisms125 = verifyNot checkBashisms "#!/bin/busybox sh\ntype -p test"
219220
prop_checkBashisms126 = verifyNot checkBashisms "#!/bin/busybox sh\nread -p foo -r bar"
220221
prop_checkBashisms127 = verifyNot checkBashisms "#!/bin/busybox sh\necho -ne foo"
222+
prop_checkBashisms128 = verify checkBashisms "#!/bin/dash\ntype -p test"
221223
checkBashisms = ForShell [Sh, Dash, BusyboxSh] $ \t -> do
222224
params <- ask
223225
kludge params t
@@ -272,6 +274,8 @@ checkBashisms = ForShell [Sh, Dash, BusyboxSh] $ \t -> do
272274
warnMsg id 3016 "unary -v (in place of [ -n \"${var+x}\" ]) is"
273275
bashism (TC_Unary id _ "-a" _) =
274276
warnMsg id 3017 "unary -a in place of -e is"
277+
bashism (TC_Unary id _ "-o" _) =
278+
warnMsg id 3062 "unary -o to check options is"
275279
bashism (T_SimpleCommand id _ [asStr -> Just "test", asStr -> Just "-a", _]) =
276280
warnMsg id 3017 "unary -a in place of -e is"
277281
bashism (TA_Unary id op _)
@@ -649,5 +653,22 @@ checkBangAfterPipe = ForShell [Dash, BusyboxSh, Sh, Bash] f
649653
err id 2326 "! is not allowed in the middle of pipelines. Use command group as in cmd | { ! cmd; } if necessary."
650654
_ -> return ()
651655

656+
657+
prop_checkNegatedUnaryOps1 = verify checkNegatedUnaryOps "[ ! -o braceexpand ]"
658+
prop_checkNegatedUnaryOps2 = verifyNot checkNegatedUnaryOps "[ -o braceexpand ]"
659+
prop_checkNegatedUnaryOps3 = verifyNot checkNegatedUnaryOps "[[ ! -o braceexpand ]]"
660+
prop_checkNegatedUnaryOps4 = verifyNot checkNegatedUnaryOps "! [ -o braceexpand ]"
661+
prop_checkNegatedUnaryOps5 = verify checkNegatedUnaryOps "[ ! -a file ]"
662+
checkNegatedUnaryOps = ForShell [Bash] f
663+
where
664+
f token = case token of
665+
TC_Unary id SingleBracket "!" (TC_Unary _ _ op _) | op `elem` ["-a", "-o"] ->
666+
err id 2332 $ msg op
667+
_ -> return ()
668+
669+
msg "-o" = "[ ! -o opt ] is always true because -o becomes logical OR. Use [[ ]] or ! [ -o opt ]."
670+
msg "-a" = "[ ! -a file ] is always true because -a becomes logical AND. Use -e instead."
671+
msg _ = pleaseReport "unhandled negated unary message"
672+
652673
return []
653674
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])

0 commit comments

Comments
 (0)