Merge branch 'es/chainlint'
The chainlint test script linter in the test suite has been updated. * es/chainlint: chainlint.sed: stop splitting "(..." into separate lines "(" and "..." chainlint.sed: swallow comments consistently chainlint.sed: stop throwing away here-doc tags chainlint.sed: don't mistake `<< word` in string as here-doc operator chainlint.sed: make here-doc "<<-" operator recognition more POSIX-like chainlint.sed: drop subshell-closing ">" annotation chainlint.sed: drop unnecessary distinction between ?!AMP?! and ?!SEMI?! chainlint.sed: tolerate harmless ";" at end of last line in block chainlint.sed: improve ?!SEMI?! placement accuracy chainlint.sed: improve ?!AMP?! placement accuracy t/Makefile: optimize chainlint self-test t/chainlint/one-liner: avoid overly intimate chainlint.sed knowledge t/chainlint/*.test: generalize self-test commentary t/chainlint/*.test: fix invalid test cases due to mixing quote types t/chainlint/*.test: don't use invalid shell syntax
This commit is contained in:
commit
d52da62801
t
Makefilechainlint.sed
chainlint
arithmetic-expansion.expectbash-array.expectblank-line.expectblank-line.testblock-comment.expectblock-comment.testblock.expectblock.testbroken-chain.expectbroken-chain.testcase-comment.expectcase-comment.testcase.expectcase.testclose-nested-and-parent-together.expectclose-subshell.expectcommand-substitution.expectcomment.expectcomplex-if-in-cuddled-loop.expectcomplex-if-in-cuddled-loop.testcuddled-if-then-else.expectcuddled-if-then-else.testcuddled-loop.expectcuddled-loop.testcuddled.expectcuddled.testexit-loop.expectexit-subshell.expectfor-loop.expectfor-loop.testhere-doc-close-subshell.expecthere-doc-multi-line-command-subst.expecthere-doc-multi-line-string.expecthere-doc.expecthere-doc.testif-in-loop.expectif-in-loop.testif-then-else.expectif-then-else.testincomplete-line.expectinline-comment.expectloop-in-if.expectloop-in-if.testmulti-line-nested-command-substitution.expectmulti-line-string.expectmulti-line-string.testnegated-one-liner.expectnested-cuddled-subshell.expectnested-here-doc.expectnested-subshell-comment.expectnested-subshell-comment.testnested-subshell.expectnested-subshell.testnot-heredoc.expectnot-heredoc.testone-liner.expectone-liner.testp4-filespec.expectpipe.expectpipe.testsemicolon.expectsemicolon.testsubshell-here-doc.expectsubshell-here-doc.testsubshell-one-liner.expectt7900-subtree.expectt7900-subtree.testwhile-loop.expectwhile-loop.test
10
t/Makefile
10
t/Makefile
@ -71,12 +71,10 @@ clean-chainlint:
|
|||||||
|
|
||||||
check-chainlint:
|
check-chainlint:
|
||||||
@mkdir -p '$(CHAINLINTTMP_SQ)' && \
|
@mkdir -p '$(CHAINLINTTMP_SQ)' && \
|
||||||
err=0 && \
|
sed -e '/^# LINT: /d' $(patsubst %,chainlint/%.test,$(CHAINLINTTESTS)) >'$(CHAINLINTTMP_SQ)'/tests && \
|
||||||
for i in $(CHAINLINTTESTS); do \
|
sed -e '/^[ ]*$$/d' $(patsubst %,chainlint/%.expect,$(CHAINLINTTESTS)) >'$(CHAINLINTTMP_SQ)'/expect && \
|
||||||
$(CHAINLINT) <chainlint/$$i.test | \
|
$(CHAINLINT) '$(CHAINLINTTMP_SQ)'/tests | grep -v '^[ ]*$$' >'$(CHAINLINTTMP_SQ)'/actual && \
|
||||||
sed -e '/^# LINT: /d' >'$(CHAINLINTTMP_SQ)'/$$i.actual && \
|
diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual
|
||||||
diff -u chainlint/$$i.expect '$(CHAINLINTTMP_SQ)'/$$i.actual || err=1; \
|
|
||||||
done && exit $$err
|
|
||||||
|
|
||||||
test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
|
test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
|
||||||
test-lint-filenames
|
test-lint-filenames
|
||||||
|
124
t/chainlint.sed
124
t/chainlint.sed
@ -24,9 +24,9 @@
|
|||||||
# in order to avoid misinterpreting the ")" in constructs such as "x=$(...)"
|
# in order to avoid misinterpreting the ")" in constructs such as "x=$(...)"
|
||||||
# and "case $x in *)" as ending the subshell.
|
# and "case $x in *)" as ending the subshell.
|
||||||
#
|
#
|
||||||
# Lines missing a final "&&" are flagged with "?!AMP?!", and lines which chain
|
# Lines missing a final "&&" are flagged with "?!AMP?!", as are lines which
|
||||||
# commands with ";" internally rather than "&&" are flagged "?!SEMI?!". A line
|
# chain commands with ";" internally rather than "&&". A line may be flagged
|
||||||
# may be flagged for both violations.
|
# for both violations.
|
||||||
#
|
#
|
||||||
# Detection of a missing &&-link in a multi-line subshell is complicated by the
|
# Detection of a missing &&-link in a multi-line subshell is complicated by the
|
||||||
# fact that the last statement before the closing ")" must not end with "&&".
|
# fact that the last statement before the closing ")" must not end with "&&".
|
||||||
@ -47,8 +47,8 @@
|
|||||||
# "?!AMP?!" violation is removed from the "bar" line (retrieved from the "hold"
|
# "?!AMP?!" violation is removed from the "bar" line (retrieved from the "hold"
|
||||||
# area) since the final statement of a subshell must not end with "&&". The
|
# area) since the final statement of a subshell must not end with "&&". The
|
||||||
# final line of a subshell may still break the &&-chain by using ";" internally
|
# final line of a subshell may still break the &&-chain by using ";" internally
|
||||||
# to chain commands together rather than "&&", so "?!SEMI?!" is never removed
|
# to chain commands together rather than "&&", but an internal "?!AMP?!" is
|
||||||
# from a line (even though "?!AMP?!" might be).
|
# never removed from a line even though a line-ending "?!AMP?!" might be.
|
||||||
#
|
#
|
||||||
# Care is taken to recognize the last _statement_ of a multi-line subshell, not
|
# Care is taken to recognize the last _statement_ of a multi-line subshell, not
|
||||||
# necessarily the last textual _line_ within the subshell, since &&-chaining
|
# necessarily the last textual _line_ within the subshell, since &&-chaining
|
||||||
@ -62,26 +62,20 @@
|
|||||||
# receives similar treatment.
|
# receives similar treatment.
|
||||||
#
|
#
|
||||||
# Swallowing here-docs with arbitrary tags requires a bit of finesse. When a
|
# Swallowing here-docs with arbitrary tags requires a bit of finesse. When a
|
||||||
# line such as "cat <<EOF >out" is seen, the here-doc tag is moved to the front
|
# line such as "cat <<EOF" is seen, the here-doc tag is copied to the front of
|
||||||
# of the line enclosed in angle brackets as a sentinel, giving "<EOF>cat >out".
|
# the line enclosed in angle brackets as a sentinel, giving "<EOF>cat <<EOF".
|
||||||
# As each subsequent line is read, it is appended to the target line and a
|
# As each subsequent line is read, it is appended to the target line and a
|
||||||
# (whitespace-loose) back-reference match /^<(.*)>\n\1$/ is attempted to see if
|
# (whitespace-loose) back-reference match /^<(.*)>\n\1$/ is attempted to see if
|
||||||
# the content inside "<...>" matches the entirety of the newly-read line. For
|
# the content inside "<...>" matches the entirety of the newly-read line. For
|
||||||
# instance, if the next line read is "some data", when concatenated with the
|
# instance, if the next line read is "some data", when concatenated with the
|
||||||
# target line, it becomes "<EOF>cat >out\nsome data", and a match is attempted
|
# target line, it becomes "<EOF>cat <<EOF\nsome data", and a match is attempted
|
||||||
# to see if "EOF" matches "some data". Since it doesn't, the next line is
|
# to see if "EOF" matches "some data". Since it doesn't, the next line is
|
||||||
# attempted. When a line consisting of only "EOF" (and possible whitespace) is
|
# attempted. When a line consisting of only "EOF" (and possible whitespace) is
|
||||||
# encountered, it is appended to the target line giving "<EOF>cat >out\nEOF",
|
# encountered, it is appended to the target line giving "<EOF>cat <<EOF\nEOF",
|
||||||
# in which case the "EOF" inside "<...>" does match the text following the
|
# in which case the "EOF" inside "<...>" does match the text following the
|
||||||
# newline, thus the closing here-doc tag has been found. The closing tag line
|
# newline, thus the closing here-doc tag has been found. The closing tag line
|
||||||
# and the "<...>" prefix on the target line are then discarded, leaving just
|
# and the "<...>" prefix on the target line are then discarded, leaving just
|
||||||
# the target line "cat >out".
|
# the target line "cat <<EOF".
|
||||||
#
|
|
||||||
# To facilitate regression testing (and manual debugging), a ">" annotation is
|
|
||||||
# applied to the line containing ")" which closes a subshell, ">>" to a line
|
|
||||||
# closing a nested subshell, and ">>>" to a line closing both at once. This
|
|
||||||
# makes it easy to detect whether the heuristics correctly identify
|
|
||||||
# end-of-subshell.
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
# incomplete line -- slurp up next line
|
# incomplete line -- slurp up next line
|
||||||
@ -94,9 +88,9 @@
|
|||||||
|
|
||||||
# here-doc -- swallow it to avoid false hits within its body (but keep the
|
# here-doc -- swallow it to avoid false hits within its body (but keep the
|
||||||
# command to which it was attached)
|
# command to which it was attached)
|
||||||
/<<[ ]*[-\\'"]*[A-Za-z0-9_]/ {
|
/<<-*[ ]*[\\'"]*[A-Za-z0-9_]/ {
|
||||||
s/^\(.*\)<<[ ]*[-\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1<</
|
/"[^"]*<<[^"]*"/bnotdoc
|
||||||
s/[ ]*<<//
|
s/^\(.*<<-*[ ]*\)[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1\2/
|
||||||
:hered
|
:hered
|
||||||
N
|
N
|
||||||
/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{
|
/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{
|
||||||
@ -106,6 +100,7 @@
|
|||||||
s/^<[^>]*>//
|
s/^<[^>]*>//
|
||||||
s/\n.*$//
|
s/\n.*$//
|
||||||
}
|
}
|
||||||
|
:notdoc
|
||||||
|
|
||||||
# one-liner "(...) &&"
|
# one-liner "(...) &&"
|
||||||
/^[ ]*!*[ ]*(..*)[ ]*&&[ ]*$/boneline
|
/^[ ]*!*[ ]*(..*)[ ]*&&[ ]*$/boneline
|
||||||
@ -126,7 +121,7 @@ b
|
|||||||
# "&&" (but not ";" in a string)
|
# "&&" (but not ";" in a string)
|
||||||
:oneline
|
:oneline
|
||||||
/;/{
|
/;/{
|
||||||
/"[^"]*;[^"]*"/!s/^/?!SEMI?!/
|
/"[^"]*;[^"]*"/!s/;/; ?!AMP?!/
|
||||||
}
|
}
|
||||||
b
|
b
|
||||||
|
|
||||||
@ -136,11 +131,15 @@ b
|
|||||||
h
|
h
|
||||||
bnextln
|
bnextln
|
||||||
}
|
}
|
||||||
# "(..." line -- split off and stash "(", then process "..." as its own line
|
# "(..." line -- "(" opening subshell cuddled with command; temporarily replace
|
||||||
|
# "(" with sentinel "^" and process the line as if "(" had been seen solo on
|
||||||
|
# the preceding line; this temporary replacement prevents several rules from
|
||||||
|
# accidentally thinking "(" introduces a nested subshell; "^" is changed back
|
||||||
|
# to "(" at output time
|
||||||
x
|
x
|
||||||
s/.*/(/
|
s/.*//
|
||||||
x
|
x
|
||||||
s/(//
|
s/(/^/
|
||||||
bslurp
|
bslurp
|
||||||
|
|
||||||
:nextln
|
:nextln
|
||||||
@ -157,8 +156,10 @@ s/.*\n//
|
|||||||
/"[^'"]*'[^'"]*"/!bsqstr
|
/"[^'"]*'[^'"]*"/!bsqstr
|
||||||
}
|
}
|
||||||
:folded
|
:folded
|
||||||
# here-doc -- swallow it
|
# here-doc -- swallow it (but not "<<" in a string)
|
||||||
/<<[ ]*[-\\'"]*[A-Za-z0-9_]/bheredoc
|
/<<-*[ ]*[\\'"]*[A-Za-z0-9_]/{
|
||||||
|
/"[^"]*<<[^"]*"/!bheredoc
|
||||||
|
}
|
||||||
# comment or empty line -- discard since final non-comment, non-empty line
|
# comment or empty line -- discard since final non-comment, non-empty line
|
||||||
# before closing ")", "done", "elsif", "else", or "fi" will need to be
|
# before closing ")", "done", "elsif", "else", or "fi" will need to be
|
||||||
# re-visited to drop "suspect" marking since final line of those constructs
|
# re-visited to drop "suspect" marking since final line of those constructs
|
||||||
@ -171,12 +172,12 @@ s/.*\n//
|
|||||||
/"[^"]*#[^"]*"/!s/[ ]#.*$//
|
/"[^"]*#[^"]*"/!s/[ ]#.*$//
|
||||||
}
|
}
|
||||||
# one-liner "case ... esac"
|
# one-liner "case ... esac"
|
||||||
/^[ ]*case[ ]*..*esac/bchkchn
|
/^[ ^]*case[ ]*..*esac/bchkchn
|
||||||
# multi-line "case ... esac"
|
# multi-line "case ... esac"
|
||||||
/^[ ]*case[ ]..*[ ]in/bcase
|
/^[ ^]*case[ ]..*[ ]in/bcase
|
||||||
# multi-line "for ... done" or "while ... done"
|
# multi-line "for ... done" or "while ... done"
|
||||||
/^[ ]*for[ ]..*[ ]in/bcont
|
/^[ ^]*for[ ]..*[ ]in/bcont
|
||||||
/^[ ]*while[ ]/bcont
|
/^[ ^]*while[ ]/bcont
|
||||||
/^[ ]*do[ ]/bcont
|
/^[ ]*do[ ]/bcont
|
||||||
/^[ ]*do[ ]*$/bcont
|
/^[ ]*do[ ]*$/bcont
|
||||||
/;[ ]*do/bcont
|
/;[ ]*do/bcont
|
||||||
@ -187,7 +188,7 @@ s/.*\n//
|
|||||||
/||[ ]*exit[ ]/bcont
|
/||[ ]*exit[ ]/bcont
|
||||||
/||[ ]*exit[ ]*$/bcont
|
/||[ ]*exit[ ]*$/bcont
|
||||||
# multi-line "if...elsif...else...fi"
|
# multi-line "if...elsif...else...fi"
|
||||||
/^[ ]*if[ ]/bcont
|
/^[ ^]*if[ ]/bcont
|
||||||
/^[ ]*then[ ]/bcont
|
/^[ ]*then[ ]/bcont
|
||||||
/^[ ]*then[ ]*$/bcont
|
/^[ ]*then[ ]*$/bcont
|
||||||
/;[ ]*then/bcont
|
/;[ ]*then/bcont
|
||||||
@ -200,15 +201,15 @@ s/.*\n//
|
|||||||
/^[ ]*fi[ ]*[<>|]/bdone
|
/^[ ]*fi[ ]*[<>|]/bdone
|
||||||
/^[ ]*fi[ ]*)/bdone
|
/^[ ]*fi[ ]*)/bdone
|
||||||
# nested one-liner "(...) &&"
|
# nested one-liner "(...) &&"
|
||||||
/^[ ]*(.*)[ ]*&&[ ]*$/bchkchn
|
/^[ ^]*(.*)[ ]*&&[ ]*$/bchkchn
|
||||||
# nested one-liner "(...)"
|
# nested one-liner "(...)"
|
||||||
/^[ ]*(.*)[ ]*$/bchkchn
|
/^[ ^]*(.*)[ ]*$/bchkchn
|
||||||
# nested one-liner "(...) >x" (or "2>x" or "<x" or "|x")
|
# nested one-liner "(...) >x" (or "2>x" or "<x" or "|x")
|
||||||
/^[ ]*(.*)[ ]*[0-9]*[<>|]/bchkchn
|
/^[ ^]*(.*)[ ]*[0-9]*[<>|]/bchkchn
|
||||||
# nested multi-line "(...\n...)"
|
# nested multi-line "(...\n...)"
|
||||||
/^[ ]*(/bnest
|
/^[ ^]*(/bnest
|
||||||
# multi-line "{...\n...}"
|
# multi-line "{...\n...}"
|
||||||
/^[ ]*{/bblock
|
/^[ ^]*{/bblock
|
||||||
# closing ")" on own line -- exit subshell
|
# closing ")" on own line -- exit subshell
|
||||||
/^[ ]*)/bclssolo
|
/^[ ]*)/bclssolo
|
||||||
# "$((...))" -- arithmetic expansion; not closing ")"
|
# "$((...))" -- arithmetic expansion; not closing ")"
|
||||||
@ -230,16 +231,18 @@ s/.*\n//
|
|||||||
# string and not ";;" in one-liner "case...esac")
|
# string and not ";;" in one-liner "case...esac")
|
||||||
/;/{
|
/;/{
|
||||||
/;;/!{
|
/;;/!{
|
||||||
/"[^"]*;[^"]*"/!s/^/?!SEMI?!/
|
/"[^"]*;[^"]*"/!s/;/; ?!AMP?!/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# line ends with pipe "...|" -- valid; not missing "&&"
|
# line ends with pipe "...|" -- valid; not missing "&&"
|
||||||
/|[ ]*$/bcont
|
/|[ ]*$/bcont
|
||||||
# missing end-of-line "&&" -- mark suspect
|
# missing end-of-line "&&" -- mark suspect
|
||||||
/&&[ ]*$/!s/^/?!AMP?!/
|
/&&[ ]*$/!s/$/ ?!AMP?!/
|
||||||
:cont
|
:cont
|
||||||
# retrieve and print previous line
|
# retrieve and print previous line
|
||||||
x
|
x
|
||||||
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
n
|
n
|
||||||
bslurp
|
bslurp
|
||||||
|
|
||||||
@ -280,8 +283,7 @@ bfolded
|
|||||||
# found here-doc -- swallow it to avoid false hits within its body (but keep
|
# found here-doc -- swallow it to avoid false hits within its body (but keep
|
||||||
# the command to which it was attached)
|
# the command to which it was attached)
|
||||||
:heredoc
|
:heredoc
|
||||||
s/^\(.*\)<<[ ]*[-\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1<</
|
s/^\(.*\)<<\(-*[ ]*\)[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\3>\1?!HERE?!\2\3/
|
||||||
s/[ ]*<<//
|
|
||||||
:hdocsub
|
:hdocsub
|
||||||
N
|
N
|
||||||
/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{
|
/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{
|
||||||
@ -295,7 +297,15 @@ bfolded
|
|||||||
# found "case ... in" -- pass through untouched
|
# found "case ... in" -- pass through untouched
|
||||||
:case
|
:case
|
||||||
x
|
x
|
||||||
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
n
|
n
|
||||||
|
:cascom
|
||||||
|
/^[ ]*#/{
|
||||||
|
N
|
||||||
|
s/.*\n//
|
||||||
|
bcascom
|
||||||
|
}
|
||||||
/^[ ]*esac/bslurp
|
/^[ ]*esac/bslurp
|
||||||
bcase
|
bcase
|
||||||
|
|
||||||
@ -303,7 +313,7 @@ bcase
|
|||||||
# that line legitimately lacks "&&"
|
# that line legitimately lacks "&&"
|
||||||
:else
|
:else
|
||||||
x
|
x
|
||||||
s/?!AMP?!//
|
s/\( ?!AMP?!\)* ?!AMP?!$//
|
||||||
x
|
x
|
||||||
bcont
|
bcont
|
||||||
|
|
||||||
@ -311,7 +321,7 @@ bcont
|
|||||||
# "suspect" from final contained line since that line legitimately lacks "&&"
|
# "suspect" from final contained line since that line legitimately lacks "&&"
|
||||||
:done
|
:done
|
||||||
x
|
x
|
||||||
s/?!AMP?!//
|
s/\( ?!AMP?!\)* ?!AMP?!$//
|
||||||
x
|
x
|
||||||
# is 'done' or 'fi' cuddled with ")" to close subshell?
|
# is 'done' or 'fi' cuddled with ")" to close subshell?
|
||||||
/done.*)/bclose
|
/done.*)/bclose
|
||||||
@ -322,11 +332,18 @@ bchkchn
|
|||||||
:nest
|
:nest
|
||||||
x
|
x
|
||||||
:nstslrp
|
:nstslrp
|
||||||
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
n
|
n
|
||||||
|
:nstcom
|
||||||
|
# comment -- not closing ")" if in comment
|
||||||
|
/^[ ]*#/{
|
||||||
|
N
|
||||||
|
s/.*\n//
|
||||||
|
bnstcom
|
||||||
|
}
|
||||||
# closing ")" on own line -- stop nested slurp
|
# closing ")" on own line -- stop nested slurp
|
||||||
/^[ ]*)/bnstcl
|
/^[ ]*)/bnstcl
|
||||||
# comment -- not closing ")" if in comment
|
|
||||||
/^[ ]*#/bnstcnt
|
|
||||||
# "$((...))" -- arithmetic expansion; not closing ")"
|
# "$((...))" -- arithmetic expansion; not closing ")"
|
||||||
/\$(([^)][^)]*))[^)]*$/bnstcnt
|
/\$(([^)][^)]*))[^)]*$/bnstcnt
|
||||||
# "$(...)" -- command substitution; not closing ")"
|
# "$(...)" -- command substitution; not closing ")"
|
||||||
@ -337,7 +354,6 @@ n
|
|||||||
x
|
x
|
||||||
bnstslrp
|
bnstslrp
|
||||||
:nstcl
|
:nstcl
|
||||||
s/^/>>/
|
|
||||||
# is it "))" which closes nested and parent subshells?
|
# is it "))" which closes nested and parent subshells?
|
||||||
/)[ ]*)/bslurp
|
/)[ ]*)/bslurp
|
||||||
bchkchn
|
bchkchn
|
||||||
@ -345,7 +361,15 @@ bchkchn
|
|||||||
# found multi-line "{...\n...}" block -- pass through untouched
|
# found multi-line "{...\n...}" block -- pass through untouched
|
||||||
:block
|
:block
|
||||||
x
|
x
|
||||||
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
n
|
n
|
||||||
|
:blkcom
|
||||||
|
/^[ ]*#/{
|
||||||
|
N
|
||||||
|
s/.*\n//
|
||||||
|
bblkcom
|
||||||
|
}
|
||||||
# closing "}" -- stop block slurp
|
# closing "}" -- stop block slurp
|
||||||
/}/bchkchn
|
/}/bchkchn
|
||||||
bblock
|
bblock
|
||||||
@ -354,16 +378,22 @@ bblock
|
|||||||
# since that line legitimately lacks "&&" and exit subshell loop
|
# since that line legitimately lacks "&&" and exit subshell loop
|
||||||
:clssolo
|
:clssolo
|
||||||
x
|
x
|
||||||
s/?!AMP?!//
|
s/\( ?!AMP?!\)* ?!AMP?!$//
|
||||||
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
p
|
p
|
||||||
x
|
x
|
||||||
s/^/>/
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
b
|
b
|
||||||
|
|
||||||
# found closing "...)" -- exit subshell loop
|
# found closing "...)" -- exit subshell loop
|
||||||
:close
|
:close
|
||||||
x
|
x
|
||||||
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
p
|
p
|
||||||
x
|
x
|
||||||
s/^/>/
|
s/^\([ ]*\)^/\1(/
|
||||||
|
s/?!HERE?!/<</g
|
||||||
b
|
b
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
foo &&
|
foo &&
|
||||||
bar=$((42 + 1)) &&
|
bar=$((42 + 1)) &&
|
||||||
baz
|
baz
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
?!AMP?! bar=$((42 + 1))
|
bar=$((42 + 1)) ?!AMP?!
|
||||||
baz
|
baz
|
||||||
>)
|
)
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
foo &&
|
foo &&
|
||||||
bar=(gumbo stumbo wumbo) &&
|
bar=(gumbo stumbo wumbo) &&
|
||||||
baz
|
baz
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
foo &&
|
foo &&
|
||||||
bar=${#bar[@]} &&
|
bar=${#bar[@]} &&
|
||||||
baz
|
baz
|
||||||
>)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(
|
(
|
||||||
nothing &&
|
nothing &&
|
||||||
something
|
something
|
||||||
>)
|
)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
nothing &&
|
nothing &&
|
||||||
|
|
||||||
something
|
something
|
||||||
# LINT: swallow blank lines since final _statement_ before subshell end is
|
# LINT: ignore blank lines since final _statement_ before subshell end is
|
||||||
# LINT: significant to "&&"-check, not final _line_ (which might be blank)
|
# LINT: significant to "&&"-check, not final _line_ (which might be blank)
|
||||||
|
|
||||||
|
|
||||||
|
6
t/chainlint/block-comment.expect
Normal file
6
t/chainlint/block-comment.expect
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(
|
||||||
|
{
|
||||||
|
echo a &&
|
||||||
|
echo b
|
||||||
|
}
|
||||||
|
)
|
8
t/chainlint/block-comment.test
Normal file
8
t/chainlint/block-comment.test
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
(
|
||||||
|
{
|
||||||
|
# show a
|
||||||
|
echo a &&
|
||||||
|
# show b
|
||||||
|
echo b
|
||||||
|
}
|
||||||
|
)
|
@ -7,6 +7,6 @@
|
|||||||
bar &&
|
bar &&
|
||||||
{
|
{
|
||||||
echo c
|
echo c
|
||||||
?!AMP?! }
|
} ?!AMP?!
|
||||||
baz
|
baz
|
||||||
>)
|
)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
(
|
(
|
||||||
# LINT: missing "&&" in block not currently detected (for consistency with
|
# LINT: missing "&&" after first "echo"
|
||||||
# LINT: --chain-lint at top level and to provide escape hatch if needed)
|
|
||||||
foo &&
|
foo &&
|
||||||
{
|
{
|
||||||
echo a
|
echo a
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(
|
(
|
||||||
foo &&
|
foo &&
|
||||||
?!AMP?! bar
|
bar ?!AMP?!
|
||||||
baz &&
|
baz &&
|
||||||
wop
|
wop
|
||||||
>)
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(
|
(
|
||||||
foo &&
|
foo &&
|
||||||
# LINT: missing "&&" from 'bar'
|
# LINT: missing "&&" from "bar"
|
||||||
bar
|
bar
|
||||||
baz &&
|
baz &&
|
||||||
# LINT: final statement before closing ")" legitimately lacks "&&"
|
# LINT: final statement before closing ")" legitimately lacks "&&"
|
||||||
|
8
t/chainlint/case-comment.expect
Normal file
8
t/chainlint/case-comment.expect
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
(
|
||||||
|
case "$x" in
|
||||||
|
x) foo ;;
|
||||||
|
*)
|
||||||
|
bar
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
)
|
11
t/chainlint/case-comment.test
Normal file
11
t/chainlint/case-comment.test
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
(
|
||||||
|
case "$x" in
|
||||||
|
# found foo
|
||||||
|
x) foo ;;
|
||||||
|
# found other
|
||||||
|
*)
|
||||||
|
# treat it as bar
|
||||||
|
bar
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
)
|
@ -4,16 +4,16 @@
|
|||||||
*) bar ;;
|
*) bar ;;
|
||||||
esac &&
|
esac &&
|
||||||
foobar
|
foobar
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
case "$x" in
|
case "$x" in
|
||||||
x) foo ;;
|
x) foo ;;
|
||||||
*) bar ;;
|
*) bar ;;
|
||||||
?!AMP?! esac
|
esac ?!AMP?!
|
||||||
foobar
|
foobar
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
case "$x" in 1) true;; esac &&
|
case "$x" in 1) true;; esac &&
|
||||||
?!AMP?! case "$y" in 2) false;; esac
|
case "$y" in 2) false;; esac ?!AMP?!
|
||||||
foobar
|
foobar
|
||||||
>)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
(
|
(
|
||||||
# LINT: "...)" arms in 'case' not misinterpreted as subshell-closing ")"
|
# LINT: "...)" arms in "case" not misinterpreted as subshell-closing ")"
|
||||||
case "$x" in
|
case "$x" in
|
||||||
x) foo ;;
|
x) foo ;;
|
||||||
*) bar ;;
|
*) bar ;;
|
||||||
@ -7,7 +7,7 @@
|
|||||||
foobar
|
foobar
|
||||||
) &&
|
) &&
|
||||||
(
|
(
|
||||||
# LINT: missing "&&" on 'esac'
|
# LINT: missing "&&" on "esac"
|
||||||
case "$x" in
|
case "$x" in
|
||||||
x) foo ;;
|
x) foo ;;
|
||||||
*) bar ;;
|
*) bar ;;
|
||||||
@ -15,7 +15,7 @@
|
|||||||
foobar
|
foobar
|
||||||
) &&
|
) &&
|
||||||
(
|
(
|
||||||
# LINT: "...)" arm in one-liner 'case' not misinterpreted as closing ")"
|
# LINT: "...)" arm in one-liner "case" not misinterpreted as closing ")"
|
||||||
case "$x" in 1) true;; esac &&
|
case "$x" in 1) true;; esac &&
|
||||||
# LINT: same but missing "&&"
|
# LINT: same but missing "&&"
|
||||||
case "$y" in 2) false;; esac
|
case "$y" in 2) false;; esac
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
(
|
(cd foo &&
|
||||||
cd foo &&
|
|
||||||
(bar &&
|
(bar &&
|
||||||
>>> baz))
|
baz))
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
(
|
(
|
||||||
foo
|
foo
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
bar
|
bar
|
||||||
>) >out &&
|
) >out &&
|
||||||
(
|
(
|
||||||
baz
|
baz
|
||||||
>) 2>err &&
|
) 2>err &&
|
||||||
(
|
(
|
||||||
boo
|
boo
|
||||||
>) <input &&
|
) <input &&
|
||||||
(
|
(
|
||||||
bip
|
bip
|
||||||
>) | wuzzle &&
|
) | wuzzle &&
|
||||||
(
|
(
|
||||||
bop
|
bop
|
||||||
>) | fazz fozz &&
|
) | fazz fozz &&
|
||||||
(
|
(
|
||||||
bup
|
bup
|
||||||
>) |
|
) |
|
||||||
fuzzle &&
|
fuzzle &&
|
||||||
(
|
(
|
||||||
yop
|
yop
|
||||||
>)
|
)
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
foo &&
|
foo &&
|
||||||
bar=$(gobble) &&
|
bar=$(gobble) &&
|
||||||
baz
|
baz
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
?!AMP?! bar=$(gobble blocks)
|
bar=$(gobble blocks) ?!AMP?!
|
||||||
baz
|
baz
|
||||||
>)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(
|
(
|
||||||
nothing &&
|
nothing &&
|
||||||
something
|
something
|
||||||
>)
|
)
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
(
|
(for i in a b c; do
|
||||||
for i in a b c; do
|
|
||||||
if test "$(echo $(waffle bat))" = "eleventeen" &&
|
if test "$(echo $(waffle bat))" = "eleventeen" &&
|
||||||
test "$x" = "$y"; then
|
test "$x" = "$y"; then
|
||||||
:
|
:
|
||||||
else
|
else
|
||||||
echo >file
|
echo >file
|
||||||
fi
|
fi
|
||||||
> done) &&
|
done) &&
|
||||||
test ! -f file
|
test ! -f file
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# LINT: 'for' loop cuddled with "(" and ")" and nested 'if' with complex
|
# LINT: "for" loop cuddled with "(" and ")" and nested "if" with complex
|
||||||
# LINT: multi-line condition; indented with spaces, not tabs
|
# LINT: multi-line condition; indented with spaces, not tabs
|
||||||
(for i in a b c; do
|
(for i in a b c; do
|
||||||
if test "$(echo $(waffle bat))" = "eleventeen" &&
|
if test "$(echo $(waffle bat))" = "eleventeen" &&
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
(
|
(if test -z ""; then
|
||||||
if test -z ""; then
|
|
||||||
echo empty
|
echo empty
|
||||||
else
|
else
|
||||||
echo bizzy
|
echo bizzy
|
||||||
> fi) &&
|
fi) &&
|
||||||
echo foobar
|
echo foobar
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# LINT: 'if' cuddled with "(" and ")"; indented with spaces, not tabs
|
# LINT: "if" cuddled with "(" and ")"; indented with spaces, not tabs
|
||||||
(if test -z ""; then
|
(if test -z ""; then
|
||||||
echo empty
|
echo empty
|
||||||
else
|
else
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
(
|
( while read x
|
||||||
while read x
|
|
||||||
do foobar bop || exit 1
|
do foobar bop || exit 1
|
||||||
> done <file ) &&
|
done <file ) &&
|
||||||
outside subshell
|
outside subshell
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# LINT: 'while' loop cuddled with "(" and ")", with embedded (allowed)
|
# LINT: "while" loop cuddled with "(" and ")", with embedded (allowed)
|
||||||
# LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed
|
# LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed
|
||||||
# LINT: loop; indented with spaces, not tabs
|
# LINT: loop; indented with spaces, not tabs
|
||||||
( while read x
|
( while read x
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
(
|
(cd foo &&
|
||||||
cd foo &&
|
|
||||||
bar
|
bar
|
||||||
>) &&
|
) &&
|
||||||
|
|
||||||
(
|
(cd foo ?!AMP?!
|
||||||
?!AMP?!cd foo
|
|
||||||
bar
|
bar
|
||||||
>) &&
|
) &&
|
||||||
|
|
||||||
(
|
(
|
||||||
cd foo &&
|
cd foo &&
|
||||||
> bar) &&
|
bar) &&
|
||||||
|
|
||||||
(
|
(cd foo &&
|
||||||
cd foo &&
|
bar) &&
|
||||||
> bar) &&
|
|
||||||
|
|
||||||
(
|
(cd foo ?!AMP?!
|
||||||
?!AMP?!cd foo
|
bar)
|
||||||
> bar)
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# LINT: first subshell statement cuddled with opening "("; for implementation
|
# LINT: first subshell statement cuddled with opening "("
|
||||||
# LINT: simplicity, "(..." is split into two lines, "(" and "..."
|
|
||||||
(cd foo &&
|
(cd foo &&
|
||||||
bar
|
bar
|
||||||
) &&
|
) &&
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
bar &&
|
bar &&
|
||||||
baz
|
baz
|
||||||
done
|
done
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
@ -13,7 +13,7 @@
|
|||||||
bar &&
|
bar &&
|
||||||
baz
|
baz
|
||||||
done
|
done
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
i=0 &&
|
i=0 &&
|
||||||
while test $i -lt 10
|
while test $i -lt 10
|
||||||
@ -21,4 +21,4 @@
|
|||||||
echo $i || exit
|
echo $i || exit
|
||||||
i=$(($i + 1))
|
i=$(($i + 1))
|
||||||
done
|
done
|
||||||
>)
|
)
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
foo || exit 1
|
foo || exit 1
|
||||||
bar &&
|
bar &&
|
||||||
baz
|
baz
|
||||||
>)
|
)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
(
|
(
|
||||||
for i in a b c
|
for i in a b c
|
||||||
do
|
do
|
||||||
?!AMP?! echo $i
|
echo $i ?!AMP?!
|
||||||
cat
|
cat <<-EOF
|
||||||
?!AMP?! done
|
done ?!AMP?!
|
||||||
for i in a b c; do
|
for i in a b c; do
|
||||||
echo $i &&
|
echo $i &&
|
||||||
cat $i
|
cat $i
|
||||||
done
|
done
|
||||||
>)
|
)
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
(
|
(
|
||||||
# LINT: 'for', 'do', 'done' do not need "&&"
|
# LINT: "for", "do", "done" do not need "&&"
|
||||||
for i in a b c
|
for i in a b c
|
||||||
do
|
do
|
||||||
# LINT: missing "&&" on 'echo'
|
# LINT: missing "&&" on "echo"
|
||||||
echo $i
|
echo $i
|
||||||
# LINT: last statement of while does not need "&&"
|
# LINT: last statement of while does not need "&&"
|
||||||
cat <<-\EOF
|
cat <<-\EOF
|
||||||
bar
|
bar
|
||||||
EOF
|
EOF
|
||||||
# LINT: missing "&&" on 'done'
|
# LINT: missing "&&" on "done"
|
||||||
done
|
done
|
||||||
|
|
||||||
# LINT: 'do' on same line as 'for'
|
# LINT: "do" on same line as "for"
|
||||||
for i in a b c; do
|
for i in a b c; do
|
||||||
echo $i &&
|
echo $i &&
|
||||||
cat $i
|
cat $i
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
(
|
(
|
||||||
> cat)
|
cat <<-INPUT)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
(
|
(
|
||||||
x=$(bobble &&
|
x=$(bobble <<-END &&
|
||||||
?!AMP?!>> wiffle)
|
wiffle) ?!AMP?!
|
||||||
echo $x
|
echo $x
|
||||||
>)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(
|
(
|
||||||
?!AMP?! cat && echo "multi-line string"
|
cat <<-TXT && echo "multi-line string" ?!AMP?!
|
||||||
bap
|
bap
|
||||||
>)
|
)
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
boodle wobba gorgo snoot wafta snurb &&
|
boodle wobba gorgo snoot wafta snurb <<EOF &&
|
||||||
|
|
||||||
cat >foo &&
|
cat <<-Arbitrary_Tag_42 >foo &&
|
||||||
|
|
||||||
cat >bar &&
|
cat <<zump >boo &&
|
||||||
|
|
||||||
cat >boo &&
|
horticulture <<EOF
|
||||||
|
|
||||||
horticulture
|
|
||||||
|
@ -14,13 +14,6 @@ boz
|
|||||||
woz
|
woz
|
||||||
Arbitrary_Tag_42
|
Arbitrary_Tag_42
|
||||||
|
|
||||||
# LINT: swallow 'quoted' here-doc
|
|
||||||
cat <<'FUMP' >bar &&
|
|
||||||
snoz
|
|
||||||
boz
|
|
||||||
woz
|
|
||||||
FUMP
|
|
||||||
|
|
||||||
# LINT: swallow "quoted" here-doc
|
# LINT: swallow "quoted" here-doc
|
||||||
cat <<"zump" >boo &&
|
cat <<"zump" >boo &&
|
||||||
snoz
|
snoz
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
do
|
do
|
||||||
if false
|
if false
|
||||||
then
|
then
|
||||||
?!AMP?! echo "err"
|
echo "err" ?!AMP?!
|
||||||
exit 1
|
exit 1
|
||||||
?!AMP?! fi
|
fi ?!AMP?!
|
||||||
foo
|
foo
|
||||||
?!AMP?! done
|
done ?!AMP?!
|
||||||
bar
|
bar
|
||||||
>)
|
)
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
do
|
do
|
||||||
if false
|
if false
|
||||||
then
|
then
|
||||||
# LINT: missing "&&" on 'echo'
|
# LINT: missing "&&" on "echo"
|
||||||
echo "err"
|
echo "err"
|
||||||
exit 1
|
exit 1
|
||||||
# LINT: missing "&&" on 'fi'
|
# LINT: missing "&&" on "fi"
|
||||||
fi
|
fi
|
||||||
foo
|
foo
|
||||||
# LINT: missing "&&" on 'done'
|
# LINT: missing "&&" on "done"
|
||||||
done
|
done
|
||||||
bar
|
bar
|
||||||
)
|
)
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
(
|
(
|
||||||
if test -n ""
|
if test -n ""
|
||||||
then
|
then
|
||||||
?!AMP?! echo very
|
echo very ?!AMP?!
|
||||||
echo empty
|
echo empty
|
||||||
elif test -z ""
|
elif test -z ""
|
||||||
|
then
|
||||||
echo foo
|
echo foo
|
||||||
else
|
else
|
||||||
echo foo &&
|
echo foo &&
|
||||||
cat
|
cat <<-EOF
|
||||||
?!AMP?! fi
|
fi ?!AMP?!
|
||||||
echo poodle
|
echo poodle
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
if test -n ""; then
|
if test -n ""; then
|
||||||
echo very &&
|
echo very &&
|
||||||
?!AMP?! echo empty
|
echo empty
|
||||||
if
|
fi
|
||||||
>)
|
)
|
||||||
|
@ -1,28 +1,29 @@
|
|||||||
(
|
(
|
||||||
# LINT: 'if', 'then', 'elif', 'else', 'fi' do not need "&&"
|
# LINT: "if", "then", "elif", "else", "fi" do not need "&&"
|
||||||
if test -n ""
|
if test -n ""
|
||||||
then
|
then
|
||||||
# LINT: missing "&&" on 'echo'
|
# LINT: missing "&&" on "echo"
|
||||||
echo very
|
echo very
|
||||||
# LINT: last statement before 'elif' does not need "&&"
|
# LINT: last statement before "elif" does not need "&&"
|
||||||
echo empty
|
echo empty
|
||||||
elif test -z ""
|
elif test -z ""
|
||||||
# LINT: last statement before 'else' does not need "&&"
|
then
|
||||||
|
# LINT: last statement before "else" does not need "&&"
|
||||||
echo foo
|
echo foo
|
||||||
else
|
else
|
||||||
echo foo &&
|
echo foo &&
|
||||||
# LINT: last statement before 'fi' does not need "&&"
|
# LINT: last statement before "fi" does not need "&&"
|
||||||
cat <<-\EOF
|
cat <<-\EOF
|
||||||
bar
|
bar
|
||||||
EOF
|
EOF
|
||||||
# LINT: missing "&&" on 'fi'
|
# LINT: missing "&&" on "fi"
|
||||||
fi
|
fi
|
||||||
echo poodle
|
echo poodle
|
||||||
) &&
|
) &&
|
||||||
(
|
(
|
||||||
# LINT: 'then' on same line as 'if'
|
# LINT: "then" on same line as "if"
|
||||||
if test -n ""; then
|
if test -n ""; then
|
||||||
echo very &&
|
echo very &&
|
||||||
echo empty
|
echo empty
|
||||||
if
|
fi
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
line 1 line 2 line 3 line 4 &&
|
line 1 line 2 line 3 line 4 &&
|
||||||
(
|
(
|
||||||
line 5 line 6 line 7 line 8
|
line 5 line 6 line 7 line 8
|
||||||
>)
|
)
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
(
|
(
|
||||||
foobar &&
|
foobar &&
|
||||||
?!AMP?! barfoo
|
barfoo ?!AMP?!
|
||||||
flibble "not a # comment"
|
flibble "not a # comment"
|
||||||
>) &&
|
) &&
|
||||||
|
|
||||||
(
|
(cd foo &&
|
||||||
cd foo &&
|
flibble "not a # comment")
|
||||||
> flibble "not a # comment")
|
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
then
|
then
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
?!AMP?! echo "pop"
|
echo "pop" ?!AMP?!
|
||||||
echo "glup"
|
echo "glup"
|
||||||
?!AMP?! done
|
done ?!AMP?!
|
||||||
foo
|
foo
|
||||||
?!AMP?! fi
|
fi ?!AMP?!
|
||||||
bar
|
bar
|
||||||
>)
|
)
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
then
|
then
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
# LINT: missing "&&" on 'echo'
|
# LINT: missing "&&" on "echo"
|
||||||
echo "pop"
|
echo "pop"
|
||||||
echo "glup"
|
echo "glup"
|
||||||
# LINT: missing "&&" on 'done'
|
# LINT: missing "&&" on "done"
|
||||||
done
|
done
|
||||||
foo
|
foo
|
||||||
# LINT: missing "&&" on 'fi'
|
# LINT: missing "&&" on "fi"
|
||||||
fi
|
fi
|
||||||
bar
|
bar
|
||||||
)
|
)
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
x=$(
|
x=$(
|
||||||
echo bar |
|
echo bar |
|
||||||
cat
|
cat
|
||||||
>> ) &&
|
) &&
|
||||||
echo ok
|
echo ok
|
||||||
>) |
|
) |
|
||||||
sort &&
|
sort &&
|
||||||
(
|
(
|
||||||
bar &&
|
bar &&
|
||||||
x=$(echo bar |
|
x=$(echo bar |
|
||||||
cat
|
cat
|
||||||
>> ) &&
|
) &&
|
||||||
y=$(echo baz |
|
y=$(echo baz |
|
||||||
>> fip) &&
|
fip) &&
|
||||||
echo fail
|
echo fail
|
||||||
>)
|
)
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
(
|
(
|
||||||
x="line 1 line 2 line 3" &&
|
x="line 1 line 2 line 3" &&
|
||||||
?!AMP?! y='line 1 line2'
|
y="line 1 line2" ?!AMP?!
|
||||||
foobar
|
foobar
|
||||||
>) &&
|
) &&
|
||||||
(
|
|
||||||
echo "there's nothing to see here" &&
|
|
||||||
exit
|
|
||||||
>) &&
|
|
||||||
(
|
(
|
||||||
echo "xyz" "abc def ghi" &&
|
echo "xyz" "abc def ghi" &&
|
||||||
echo 'xyz' 'abc def ghi' &&
|
|
||||||
echo 'xyz' "abc def ghi" &&
|
|
||||||
barfoo
|
barfoo
|
||||||
>)
|
)
|
||||||
|
@ -3,25 +3,13 @@
|
|||||||
line 2
|
line 2
|
||||||
line 3" &&
|
line 3" &&
|
||||||
# LINT: missing "&&" on assignment
|
# LINT: missing "&&" on assignment
|
||||||
y='line 1
|
y="line 1
|
||||||
line2'
|
line2"
|
||||||
foobar
|
foobar
|
||||||
) &&
|
) &&
|
||||||
(
|
|
||||||
# LINT: apostrophe (in a contraction) within string not misinterpreted as
|
|
||||||
# LINT: starting multi-line single-quoted string
|
|
||||||
echo "there's nothing to see here" &&
|
|
||||||
exit
|
|
||||||
) &&
|
|
||||||
(
|
(
|
||||||
echo "xyz" "abc
|
echo "xyz" "abc
|
||||||
def
|
def
|
||||||
ghi" &&
|
ghi" &&
|
||||||
echo 'xyz' 'abc
|
|
||||||
def
|
|
||||||
ghi' &&
|
|
||||||
echo 'xyz' "abc
|
|
||||||
def
|
|
||||||
ghi" &&
|
|
||||||
barfoo
|
barfoo
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
! (foo && bar) &&
|
! (foo && bar) &&
|
||||||
! (foo && bar) >baz &&
|
! (foo && bar) >baz &&
|
||||||
|
|
||||||
?!SEMI?!! (foo; bar) &&
|
! (foo; ?!AMP?! bar) &&
|
||||||
?!SEMI?!! (foo; bar) >baz
|
! (foo; ?!AMP?! bar) >baz
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
(
|
(
|
||||||
(cd foo &&
|
(cd foo &&
|
||||||
bar
|
bar
|
||||||
>> ) &&
|
) &&
|
||||||
(cd foo &&
|
(cd foo &&
|
||||||
bar
|
bar
|
||||||
?!AMP?!>> )
|
) ?!AMP?!
|
||||||
(
|
(
|
||||||
cd foo &&
|
cd foo &&
|
||||||
>> bar) &&
|
bar) &&
|
||||||
(
|
(
|
||||||
cd foo &&
|
cd foo &&
|
||||||
?!AMP?!>> bar)
|
bar) ?!AMP?!
|
||||||
(cd foo &&
|
(cd foo &&
|
||||||
>> bar) &&
|
bar) &&
|
||||||
(cd foo &&
|
(cd foo &&
|
||||||
?!AMP?!>> bar)
|
bar) ?!AMP?!
|
||||||
foobar
|
foobar
|
||||||
>)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
cat >foop &&
|
cat <<ARBITRARY >foop &&
|
||||||
|
|
||||||
(
|
(
|
||||||
cat &&
|
cat <<-INPUT_END &&
|
||||||
?!AMP?! cat
|
cat <<-EOT ?!AMP?!
|
||||||
foobar
|
foobar
|
||||||
>)
|
)
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
foo &&
|
foo &&
|
||||||
(
|
(
|
||||||
bar &&
|
bar &&
|
||||||
# bottles wobble while fiddles gobble
|
|
||||||
# minor numbers of cows (or do they?)
|
|
||||||
baz &&
|
baz &&
|
||||||
snaff
|
snaff
|
||||||
?!AMP?!>> )
|
) ?!AMP?!
|
||||||
fuzzy
|
fuzzy
|
||||||
>)
|
)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
# minor numbers of cows (or do they?)
|
# minor numbers of cows (or do they?)
|
||||||
baz &&
|
baz &&
|
||||||
snaff
|
snaff
|
||||||
# LINT: missing "&&" on ')'
|
# LINT: missing "&&" on ")"
|
||||||
)
|
)
|
||||||
fuzzy
|
fuzzy
|
||||||
)
|
)
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
(
|
(
|
||||||
echo a &&
|
echo a &&
|
||||||
echo b
|
echo b
|
||||||
>> ) >file &&
|
) >file &&
|
||||||
cd foo &&
|
cd foo &&
|
||||||
(
|
(
|
||||||
echo a
|
echo a
|
||||||
echo b
|
echo b
|
||||||
>> ) >file
|
) >file
|
||||||
>)
|
)
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
cd foo &&
|
cd foo &&
|
||||||
(
|
(
|
||||||
# LINT: nested multi-line subshell not presently checked for missing "&&"
|
|
||||||
echo a
|
echo a
|
||||||
echo b
|
echo b
|
||||||
) >file
|
) >file
|
||||||
|
14
t/chainlint/not-heredoc.expect
Normal file
14
t/chainlint/not-heredoc.expect
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
echo "<<<<<<< ours" &&
|
||||||
|
echo ourside &&
|
||||||
|
echo "=======" &&
|
||||||
|
echo theirside &&
|
||||||
|
echo ">>>>>>> theirs" &&
|
||||||
|
|
||||||
|
(
|
||||||
|
echo "<<<<<<< ours" &&
|
||||||
|
echo ourside &&
|
||||||
|
echo "=======" &&
|
||||||
|
echo theirside &&
|
||||||
|
echo ">>>>>>> theirs" ?!AMP?!
|
||||||
|
poodle
|
||||||
|
) >merged
|
16
t/chainlint/not-heredoc.test
Normal file
16
t/chainlint/not-heredoc.test
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# LINT: "<< ours" inside string is not here-doc
|
||||||
|
echo "<<<<<<< ours" &&
|
||||||
|
echo ourside &&
|
||||||
|
echo "=======" &&
|
||||||
|
echo theirside &&
|
||||||
|
echo ">>>>>>> theirs" &&
|
||||||
|
|
||||||
|
(
|
||||||
|
# LINT: "<< ours" inside string is not here-doc
|
||||||
|
echo "<<<<<<< ours" &&
|
||||||
|
echo ourside &&
|
||||||
|
echo "=======" &&
|
||||||
|
echo theirside &&
|
||||||
|
echo ">>>>>>> theirs"
|
||||||
|
poodle
|
||||||
|
) >merged
|
@ -2,8 +2,8 @@
|
|||||||
(foo && bar) |
|
(foo && bar) |
|
||||||
(foo && bar) >baz &&
|
(foo && bar) >baz &&
|
||||||
|
|
||||||
?!SEMI?!(foo; bar) &&
|
(foo; ?!AMP?! bar) &&
|
||||||
?!SEMI?!(foo; bar) |
|
(foo; ?!AMP?! bar) |
|
||||||
?!SEMI?!(foo; bar) >baz
|
(foo; ?!AMP?! bar) >baz &&
|
||||||
|
|
||||||
(foo "bar; baz")
|
(foo "bar; baz")
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
(foo && bar) |
|
(foo && bar) |
|
||||||
(foo && bar) >baz &&
|
(foo && bar) >baz &&
|
||||||
|
|
||||||
# LINT: top-level one-liner subshell missing internal "&&"
|
# LINT: top-level one-liner subshell missing internal "&&" and broken &&-chain
|
||||||
(foo; bar) &&
|
(foo; bar) &&
|
||||||
(foo; bar) |
|
(foo; bar) |
|
||||||
(foo; bar) >baz
|
(foo; bar) >baz &&
|
||||||
|
|
||||||
# LINT: ";" in string not misinterpreted as broken &&-chain
|
# LINT: ";" in string not misinterpreted as broken &&-chain
|
||||||
(foo "bar; baz")
|
(foo "bar; baz")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(
|
(
|
||||||
p4 print -1 //depot/fiddle#42 >file &&
|
p4 print -1 //depot/fiddle#42 >file &&
|
||||||
foobar
|
foobar
|
||||||
>)
|
)
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
bar |
|
bar |
|
||||||
baz &&
|
baz &&
|
||||||
fish |
|
fish |
|
||||||
?!AMP?! cow
|
cow ?!AMP?!
|
||||||
sunder
|
sunder
|
||||||
>)
|
)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
bar |
|
bar |
|
||||||
baz &&
|
baz &&
|
||||||
|
|
||||||
# LINT: final line of pipe sequence ('cow') lacking "&&"
|
# LINT: final line of pipe sequence ("cow") lacking "&&"
|
||||||
fish |
|
fish |
|
||||||
cow
|
cow
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
(
|
(
|
||||||
?!AMP?!?!SEMI?! cat foo ; echo bar
|
cat foo ; ?!AMP?! echo bar ?!AMP?!
|
||||||
?!SEMI?! cat foo ; echo bar
|
cat foo ; ?!AMP?! echo bar
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
?!SEMI?! cat foo ; echo bar &&
|
cat foo ; ?!AMP?! echo bar &&
|
||||||
?!SEMI?! cat foo ; echo bar
|
cat foo ; ?!AMP?! echo bar
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
echo "foo; bar" &&
|
echo "foo; bar" &&
|
||||||
?!SEMI?! cat foo; echo bar
|
cat foo; ?!AMP?! echo bar
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
?!SEMI?! foo;
|
foo;
|
||||||
>) &&
|
) &&
|
||||||
(
|
(cd foo &&
|
||||||
cd foo &&
|
|
||||||
for i in a b c; do
|
for i in a b c; do
|
||||||
?!SEMI?! echo;
|
echo;
|
||||||
> done)
|
done)
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
cat foo; echo bar
|
cat foo; echo bar
|
||||||
) &&
|
) &&
|
||||||
(
|
(
|
||||||
# LINT: unnecessary terminating semicolon
|
# LINT: semicolon unnecessary but legitimate
|
||||||
foo;
|
foo;
|
||||||
) &&
|
) &&
|
||||||
(cd foo &&
|
(cd foo &&
|
||||||
for i in a b c; do
|
for i in a b c; do
|
||||||
# LINT: unnecessary terminating semicolon
|
# LINT: semicolon unnecessary but legitimate
|
||||||
echo;
|
echo;
|
||||||
done)
|
done)
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
(
|
(
|
||||||
echo wobba gorgo snoot wafta snurb &&
|
echo wobba gorgo snoot wafta snurb <<-EOF &&
|
||||||
?!AMP?! cat >bip
|
cat <<EOF >bip ?!AMP?!
|
||||||
echo >bop
|
echo <<-EOF >bop
|
||||||
>) &&
|
) &&
|
||||||
(
|
(
|
||||||
cat >bup &&
|
cat <<-ARBITRARY >bup &&
|
||||||
cat >bup2 &&
|
cat <<-ARBITRARY3 >bup3 &&
|
||||||
cat >bup3 &&
|
|
||||||
meep
|
meep
|
||||||
>)
|
)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
nevermore...
|
nevermore...
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# LINT: missing "&&" on 'cat'
|
# LINT: missing "&&" on "cat"
|
||||||
cat <<EOF >bip
|
cat <<EOF >bip
|
||||||
fish fly high
|
fish fly high
|
||||||
EOF
|
EOF
|
||||||
@ -27,10 +27,6 @@
|
|||||||
glink
|
glink
|
||||||
FIZZ
|
FIZZ
|
||||||
ARBITRARY
|
ARBITRARY
|
||||||
cat <<-'ARBITRARY2' >bup2 &&
|
|
||||||
glink
|
|
||||||
FIZZ
|
|
||||||
ARBITRARY2
|
|
||||||
cat <<-"ARBITRARY3" >bup3 &&
|
cat <<-"ARBITRARY3" >bup3 &&
|
||||||
glink
|
glink
|
||||||
FIZZ
|
FIZZ
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
(foo && bar) &&
|
(foo && bar) &&
|
||||||
(foo && bar) |
|
(foo && bar) |
|
||||||
(foo && bar) >baz &&
|
(foo && bar) >baz &&
|
||||||
?!SEMI?! (foo; bar) &&
|
(foo; ?!AMP?! bar) &&
|
||||||
?!SEMI?! (foo; bar) |
|
(foo; ?!AMP?! bar) |
|
||||||
?!SEMI?! (foo; bar) >baz &&
|
(foo; ?!AMP?! bar) >baz &&
|
||||||
(foo || exit 1) &&
|
(foo || exit 1) &&
|
||||||
(foo || exit 1) |
|
(foo || exit 1) |
|
||||||
(foo || exit 1) >baz &&
|
(foo || exit 1) >baz &&
|
||||||
?!AMP?! (foo && bar)
|
(foo && bar) ?!AMP?!
|
||||||
?!AMP?!?!SEMI?! (foo && bar; baz)
|
(foo && bar; ?!AMP?! baz) ?!AMP?!
|
||||||
foobar
|
foobar
|
||||||
>)
|
)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
(
|
(
|
||||||
chks="sub1sub2sub3sub4" &&
|
chks="sub1sub2sub3sub4" &&
|
||||||
chks_sub=$(cat | sed 's,^,sub dir/,'
|
chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
|
||||||
>>) &&
|
) &&
|
||||||
chkms="main-sub1main-sub2main-sub3main-sub4" &&
|
chkms="main-sub1main-sub2main-sub3main-sub4" &&
|
||||||
chkms_sub=$(cat | sed 's,^,sub dir/,'
|
chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
|
||||||
>>) &&
|
) &&
|
||||||
subfiles=$(git ls-files) &&
|
subfiles=$(git ls-files) &&
|
||||||
check_equal "$subfiles" "$chkms$chks"
|
check_equal "$subfiles" "$chkms$chks"
|
||||||
>)
|
)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
sub2
|
sub2
|
||||||
sub3
|
sub3
|
||||||
sub4" &&
|
sub4" &&
|
||||||
chks_sub=$(cat <<TXT | sed 's,^,sub dir/,'
|
chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
|
||||||
$chks
|
$chks
|
||||||
TXT
|
TXT
|
||||||
) &&
|
) &&
|
||||||
@ -11,7 +11,7 @@ TXT
|
|||||||
main-sub2
|
main-sub2
|
||||||
main-sub3
|
main-sub3
|
||||||
main-sub4" &&
|
main-sub4" &&
|
||||||
chkms_sub=$(cat <<TXT | sed 's,^,sub dir/,'
|
chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
|
||||||
$chkms
|
$chkms
|
||||||
TXT
|
TXT
|
||||||
) &&
|
) &&
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
(
|
(
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
?!AMP?! echo foo
|
echo foo ?!AMP?!
|
||||||
cat
|
cat <<-EOF
|
||||||
?!AMP?! done
|
done ?!AMP?!
|
||||||
while true; do
|
while true; do
|
||||||
echo foo &&
|
echo foo &&
|
||||||
cat bar
|
cat bar
|
||||||
done
|
done
|
||||||
>)
|
)
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
(
|
(
|
||||||
# LINT: 'while, 'do', 'done' do not need "&&"
|
# LINT: "while", "do", "done" do not need "&&"
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
# LINT: missing "&&" on 'echo'
|
# LINT: missing "&&" on "echo"
|
||||||
echo foo
|
echo foo
|
||||||
# LINT: last statement of while does not need "&&"
|
# LINT: last statement of while does not need "&&"
|
||||||
cat <<-\EOF
|
cat <<-\EOF
|
||||||
bar
|
bar
|
||||||
EOF
|
EOF
|
||||||
# LINT: missing "&&" on 'done'
|
# LINT: missing "&&" on "done"
|
||||||
done
|
done
|
||||||
|
|
||||||
# LINT: 'do' on same line as 'while'
|
# LINT: "do" on same line as "while"
|
||||||
while true; do
|
while true; do
|
||||||
echo foo &&
|
echo foo &&
|
||||||
cat bar
|
cat bar
|
||||||
|
Loading…
x
Reference in New Issue
Block a user