Skip to content

Commit

Permalink
SC2325/SC2326: Warn about ! ! foo and foo | ! bar (fixes #2810)
Browse files Browse the repository at this point in the history
  • Loading branch information
koalaman committed Jul 31, 2023
1 parent 9490b94 commit dd747b2
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## Git
### Added
- SC2324: Warn when x+=1 appends instead of increments
- SC2325: Warn about multiple `!`s in dash/sh.
- SC2326: Warn about `foo | ! bar` in bash/dash/sh.

### Fixed
- source statements with here docs now work correctly
Expand Down
26 changes: 26 additions & 0 deletions src/ShellCheck/Checks/ShellSupport.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ checks = [
,checkBraceExpansionVars
,checkMultiDimensionalArrays
,checkPS1Assignments
,checkMultipleBangs
,checkBangAfterPipe
]

testChecker (ForShell _ t) =
Expand Down Expand Up @@ -566,5 +568,29 @@ checkPS1Assignments = ForShell [Bash] f
escapeRegex = mkRegex "\\\\x1[Bb]|\\\\e|\x1B|\\\\033"


prop_checkMultipleBangs1 = verify checkMultipleBangs "! ! true"
prop_checkMultipleBangs2 = verifyNot checkMultipleBangs "! true"
checkMultipleBangs = ForShell [Dash, Sh] f
where
f token = case token of
T_Banged id (T_Banged _ _) ->
err id 2325 "Multiple ! in front of pipelines are a bash/ksh extension. Use only 0 or 1."
_ -> return ()


prop_checkBangAfterPipe1 = verify checkBangAfterPipe "true | ! true"
prop_checkBangAfterPipe2 = verifyNot checkBangAfterPipe "true | ( ! true )"
prop_checkBangAfterPipe3 = verifyNot checkBangAfterPipe "! ! true | true"
checkBangAfterPipe = ForShell [Dash, Sh, Bash] f
where
f token = case token of
T_Pipeline _ _ cmds -> mapM_ check cmds
_ -> return ()

check token = case token of
T_Banged id _ ->
err id 2326 "! is not allowed in the middle of pipelines. Use command group as in cmd | { ! cmd; } if necessary."
_ -> return ()

return []
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])
22 changes: 15 additions & 7 deletions src/ShellCheck/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2296,14 +2296,18 @@ readSource t = return t
prop_readPipeline = isOk readPipeline "! cat /etc/issue | grep -i ubuntu"
prop_readPipeline2 = isWarning readPipeline "!cat /etc/issue | grep -i ubuntu"
prop_readPipeline3 = isOk readPipeline "for f; do :; done|cat"
prop_readPipeline4 = isOk readPipeline "! ! true"
prop_readPipeline5 = isOk readPipeline "true | ! true"
readPipeline = do
unexpecting "keyword/token" readKeyword
do
(T_Bang id) <- g_Bang
pipe <- readPipeSequence
return $ T_Banged id pipe
<|>
readPipeSequence
readBanged readPipeSequence

readBanged parser = do
pos <- getPosition
(T_Bang id) <- g_Bang
next <- readBanged parser
return $ T_Banged id next
<|> parser

prop_readAndOr = isOk readAndOr "grep -i lol foo || exit 1"
prop_readAndOr1 = isOk readAndOr "# shellcheck disable=1\nfoo"
Expand Down Expand Up @@ -2359,7 +2363,7 @@ readTerm = do

readPipeSequence = do
start <- startSpan
(cmds, pipes) <- sepBy1WithSeparators readCommand
(cmds, pipes) <- sepBy1WithSeparators (readBanged readCommand)
(readPipe `thenSkip` (spacing >> readLineBreak))
id <- endSpan start
spacing
Expand Down Expand Up @@ -2389,6 +2393,10 @@ readCommand = choice [
]

readCmdName = do
-- If the command name is `!` then
optional . lookAhead . try $ do
char '!'
whitespace
-- Ignore alias suppression
optional . try $ do
char '\\'
Expand Down

0 comments on commit dd747b2

Please sign in to comment.