mirror of
https://github.com/koalaman/shellcheck.git
synced 2025-09-30 00:39:19 +08:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4f5dc7094b |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build ShellCheck
|
||||
name: Build Lol
|
||||
|
||||
# Run this workflow every time a new commit pushed to your repository
|
||||
on: push
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
run: |
|
||||
mkdir source
|
||||
cabal sdist
|
||||
mv dist-newstyle/sdist/*.tar.gz source/source.tar.gz
|
||||
mv dist/*.tar.gz source/source.tar.gz
|
||||
|
||||
- name: Deduce tags
|
||||
run: |
|
||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,14 +1,13 @@
|
||||
## v0.7.2 - 2021-04-19
|
||||
## Git
|
||||
### Added
|
||||
- `disable` directives can now be a range, e.g. `disable=SC3000-SC4000`
|
||||
- SC1143: Warn about line continuations in comments
|
||||
- SC2259/SC2260: Warn when redirections override pipes
|
||||
- SC2261: Warn about multiple competing redirections
|
||||
- SC2262/SC2263: Warn about aliases declared and used in the same parsing unit
|
||||
- SC2264: Warn about wrapper functions that blatantly recurse
|
||||
- SC2265/SC2266: Warn when using & or | with test statements
|
||||
- SC2267: Warn when using xargs -i instead of -I
|
||||
- SC2268: Warn about unnecessary x-comparisons like `[ x$var = xval ]`
|
||||
- Optional avoid-x-comparisons: Style warning SC2268 for `[ x$var = xval ]`
|
||||
|
||||
### Fixed
|
||||
- SC1072/SC1073 now respond to disable annotations, though ignoring parse errors
|
||||
@@ -22,7 +21,7 @@
|
||||
- POSIX/dash unsupported feature warnings now have individual SC3xxx codes
|
||||
- SC1090: A leading `$x/` or `$(x)/` is now treated as `./` when locating files
|
||||
- SC2154: Variables appearing in -z/-n tests are no longer considered unassigned
|
||||
- SC2270-SC2285: Improved warnings about misused `=`, e.g. `${var}=42`
|
||||
- SC2270-SC2285: Improved warnings about misused =, e.g. `${var}=42`
|
||||
|
||||
|
||||
## v0.7.1 - 2020-04-04
|
||||
@@ -165,7 +164,7 @@
|
||||
- SC2204/SC2205: Warn about `( -z foo )` and `( foo -eq bar )`
|
||||
- SC2200/SC2201: Warn about brace expansion in [/[[
|
||||
- SC2198/SC2199: Warn about arrays in [/[[
|
||||
- SC2196/SC2197: Warn about deprecated egrep/fgrep
|
||||
- SC2196/SC2197: Warn about deprected egrep/fgrep
|
||||
- SC2195: Warn about unmatchable case branches
|
||||
- SC2194: Warn about constant 'case' statements
|
||||
- SC2193: Warn about `[[ file.png == *.mp3 ]]` and other unmatchables
|
||||
@@ -182,7 +181,7 @@
|
||||
### Fixed
|
||||
- `-c` no longer suggested when using `grep -o | wc`
|
||||
- Comments and whitespace are now allowed before filewide directives
|
||||
- Here doc delimiters with esoteric quoting like `foo""` are now handled
|
||||
- Here doc delimters with esoteric quoting like `foo""` are now handled
|
||||
- SC2095 about `ssh` in while read loops is now suppressed when using `-n`
|
||||
- `%(%Y%M%D)T` now recognized as a single formatter in `printf` checks
|
||||
- `grep -F` now suppresses regex related suggestions
|
||||
|
@@ -1,5 +1,5 @@
|
||||
Name: ShellCheck
|
||||
Version: 0.7.2
|
||||
Version: 0.7.1
|
||||
Synopsis: Shell script analysis tool
|
||||
License: GPL-3
|
||||
License-file: LICENSE
|
||||
|
@@ -22,7 +22,7 @@ RUN curl -L "https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-in
|
||||
ENV CABALOPTS "--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg"
|
||||
|
||||
# Prebuild the dependencies
|
||||
RUN cabal update && IFS=';' && cabal install --dependencies-only $CABALOPTS ShellCheck
|
||||
RUN cabal update && IFS=';' && cabal install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
|
||||
|
||||
# Copy the build script
|
||||
COPY build /usr/bin
|
||||
|
@@ -2,7 +2,7 @@
|
||||
set -xe
|
||||
{
|
||||
tar xzv --strip-components=1
|
||||
chmod +x striptests && ./striptests
|
||||
./striptests
|
||||
mkdir "$TARGETNAME"
|
||||
cabal update
|
||||
( IFS=';'; cabal build $CABALOPTS )
|
||||
|
@@ -21,7 +21,7 @@ RUN curl -L "https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-in
|
||||
ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections;--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg"
|
||||
|
||||
# Prebuild the dependencies
|
||||
RUN cabal update && IFS=';' && cabal install --dependencies-only $CABALOPTS ShellCheck
|
||||
RUN cabal update && IFS=';' && cabal install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
|
||||
|
||||
# Copy the build script
|
||||
COPY build /usr/bin
|
||||
|
@@ -2,7 +2,7 @@
|
||||
set -xe
|
||||
{
|
||||
tar xzv --strip-components=1
|
||||
chmod +x striptests && ./striptests
|
||||
./striptests
|
||||
mkdir "$TARGETNAME"
|
||||
cabal update
|
||||
( IFS=';'; cabal build $CABALOPTS --enable-executable-static )
|
||||
|
@@ -51,7 +51,7 @@ RUN pirun apt-get install -y ghc cabal-install
|
||||
# Finally we can build the current dependencies. This takes hours.
|
||||
ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections;--gcc-options;-Os -Wl,--gc-sections -ffunction-sections -fdata-sections"
|
||||
RUN pirun cabal update
|
||||
RUN IFS=";" && pirun cabal install --dependencies-only $CABALOPTS ShellCheck
|
||||
RUN IFS=";" && pirun cabal install --lib $CABALOPTS Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.1.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.1 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.4 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.6.0
|
||||
|
||||
# Copy the build script
|
||||
WORKDIR /pi/scratch
|
||||
|
@@ -3,7 +3,7 @@ set -xe
|
||||
cd /scratch
|
||||
{
|
||||
tar xzv --strip-components=1
|
||||
chmod +x striptests && ./striptests
|
||||
./striptests
|
||||
mkdir "$TARGETNAME"
|
||||
# This script does not cabal update because compiling anything new is slow
|
||||
( IFS=';'; cabal build $CABALOPTS --enable-executable-static )
|
||||
|
30
build/linux.ppc64le/Dockerfile
Normal file
30
build/linux.ppc64le/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV TARGET powerpc64le-linux-gnu
|
||||
ENV TARGETNAME linux.ppc64le
|
||||
|
||||
# Build dependencies
|
||||
USER root
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN apt-get update && apt-get install -y ghc automake autoconf build-essential llvm curl qemu-user-static gcc-$TARGET
|
||||
|
||||
# Build GHC
|
||||
WORKDIR /ghc
|
||||
RUN curl -L "https://downloads.haskell.org/~ghc/8.10.4/ghc-8.10.4-src.tar.xz" | tar xJ --strip-components=1
|
||||
RUN ./boot && ./configure --host x86_64-linux-gnu --build x86_64-linux-gnu --target "$TARGET" --enable-unregisterised
|
||||
RUN cp mk/flavours/quick-cross.mk mk/build.mk && make -j "$(nproc)"
|
||||
RUN make install
|
||||
RUN curl -L "https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz" | tar xJv -C /usr/local/bin
|
||||
|
||||
# Due to an apparent cabal bug, we specify our options directly to cabal
|
||||
# It won't reuse caches if ghc-options are specified in ~/.cabal/config
|
||||
ENV CABALOPTS "--ghc-options;-optl-Wl,-fuse-ld=bfd -split-sections -optc-Os -optc-Wl,--gc-sections;--with-ghc=$TARGET-ghc;--with-hc-pkg=$TARGET-ghc-pkg"
|
||||
|
||||
# Prebuild the dependencies
|
||||
#RUN cabal update && IFS=';' && cabal install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
|
||||
|
||||
# Copy the build script
|
||||
COPY build /usr/bin
|
||||
|
||||
WORKDIR /scratch
|
||||
ENTRYPOINT ["/usr/bin/build"]
|
15
build/linux.ppc64le/build
Executable file
15
build/linux.ppc64le/build
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
set -xe
|
||||
{
|
||||
tar xzv --strip-components=1
|
||||
./striptests
|
||||
mkdir "$TARGETNAME"
|
||||
cabal update
|
||||
( IFS=';'; cabal build $CABALOPTS --enable-executable-static )
|
||||
find . -name shellcheck -type f -exec mv {} "$TARGETNAME/" \;
|
||||
ls -l "$TARGETNAME"
|
||||
"$TARGET-strip" -s "$TARGETNAME/shellcheck"
|
||||
ls -l "$TARGETNAME"
|
||||
qemu-ppc64le-static "$TARGETNAME/shellcheck" --version
|
||||
} >&2
|
||||
tar czv "$TARGETNAME"
|
1
build/linux.ppc64le/tag
Normal file
1
build/linux.ppc64le/tag
Normal file
@@ -0,0 +1 @@
|
||||
koalaman/scbuilder-linux-ppc64le
|
@@ -2,7 +2,7 @@
|
||||
set -xe
|
||||
{
|
||||
tar xzv --strip-components=1
|
||||
chmod +x striptests && ./striptests
|
||||
./striptests
|
||||
mkdir "$TARGETNAME"
|
||||
cabal update
|
||||
( IFS=';'; cabal build $CABALOPTS --enable-executable-static )
|
||||
|
@@ -5,7 +5,7 @@ ENV TARGETNAME windows.x86_64
|
||||
# We don't need wine32, even though it complains
|
||||
USER root
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN apt-get update && apt-get install -y curl busybox wine winbind
|
||||
RUN apt-get update && apt-get install -y curl busybox wine
|
||||
|
||||
# Fetch Windows version, will be available under z:\haskell
|
||||
WORKDIR /haskell
|
||||
@@ -19,8 +19,8 @@ ENV WINEPATH /haskell/bin
|
||||
# that necessitated this but I don't care enough to find out
|
||||
ENV CABALOPTS "--ghc-options;-split-sections -optc-Os -optc-Wl,--gc-sections"
|
||||
|
||||
# Precompile some deps to speed up later builds
|
||||
RUN wine /haskell/bin/cabal.exe update && IFS=';' && wine /haskell/bin/cabal.exe install --lib --dependencies-only $CABALOPTS ShellCheck
|
||||
# Precompile some deps to speed up later builds. This list is just copied from `cabal build`
|
||||
RUN wine /haskell/bin/cabal.exe update && IFS=';' && wine /haskell/bin/cabal.exe install $CABALOPTS --lib Diff-0.4.0 base-compat-0.11.2 base-orphans-0.8.4 dlist-1.0 hashable-1.3.0.0 indexed-traversable-0.1.1 integer-logarithms-1.0.3.1 primitive-0.7.1.0 regex-base-0.94.0.0 splitmix-0.1.0.3 tagged-0.8.6.1 th-abstraction-0.4.2.0 transformers-compat-0.6.6 base-compat-batteries-0.11.2 time-compat-1.9.5 unordered-containers-0.2.13.0 data-fix-0.3.1 vector-0.12.2.0 scientific-0.3.6.2 regex-tdfa-1.3.1.0 random-1.2.0 distributive-0.6.2.1 attoparsec-0.13.2.5 uuid-types-1.0.3 comonad-5.0.8 bifunctors-5.5.10 assoc-1.0.2 these-1.1.1.1 strict-0.4.0.1 aeson-1.5.5.1
|
||||
|
||||
COPY build /usr/bin
|
||||
WORKDIR /scratch
|
||||
|
@@ -6,7 +6,7 @@ cabal() {
|
||||
set -xe
|
||||
{
|
||||
tar xzv --strip-components=1
|
||||
chmod +x striptests && ./striptests
|
||||
./striptests
|
||||
mkdir "$TARGETNAME"
|
||||
cabal update
|
||||
( IFS=';'; cabal build $CABALOPTS )
|
||||
|
@@ -17,11 +17,9 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
module ShellCheck.ASTLib where
|
||||
|
||||
import ShellCheck.AST
|
||||
import ShellCheck.Regex
|
||||
|
||||
import Control.Monad.Writer
|
||||
import Control.Monad
|
||||
@@ -33,8 +31,6 @@ import Data.Maybe
|
||||
import qualified Data.Map as Map
|
||||
import Numeric (showHex)
|
||||
|
||||
import Test.QuickCheck
|
||||
|
||||
arguments (T_SimpleCommand _ _ (cmd:args)) = args
|
||||
|
||||
-- Is this a type of loop?
|
||||
@@ -676,43 +672,3 @@ isAnnotationIgnoringCode code t =
|
||||
where
|
||||
hasNum (DisableComment from to) = code >= from && code < to
|
||||
hasNum _ = False
|
||||
|
||||
prop_executableFromShebang1 = executableFromShebang "/bin/sh" == "sh"
|
||||
prop_executableFromShebang2 = executableFromShebang "/bin/bash" == "bash"
|
||||
prop_executableFromShebang3 = executableFromShebang "/usr/bin/env ksh" == "ksh"
|
||||
prop_executableFromShebang4 = executableFromShebang "/usr/bin/env -S foo=bar bash -x" == "bash"
|
||||
prop_executableFromShebang5 = executableFromShebang "/usr/bin/env --split-string=bash -x" == "bash"
|
||||
prop_executableFromShebang6 = executableFromShebang "/usr/bin/env --split-string=foo=bar bash -x" == "bash"
|
||||
prop_executableFromShebang7 = executableFromShebang "/usr/bin/env --split-string bash -x" == "bash"
|
||||
prop_executableFromShebang8 = executableFromShebang "/usr/bin/env --split-string foo=bar bash -x" == "bash"
|
||||
prop_executableFromShebang9 = executableFromShebang "/usr/bin/env foo=bar dash" == "dash"
|
||||
prop_executableFromShebang10 = executableFromShebang "/bin/busybox sh" == "ash"
|
||||
prop_executableFromShebang11 = executableFromShebang "/bin/busybox ash" == "ash"
|
||||
|
||||
-- Get the shell executable from a string like '/usr/bin/env bash'
|
||||
executableFromShebang :: String -> String
|
||||
executableFromShebang = shellFor
|
||||
where
|
||||
re = mkRegex "/env +(-S|--split-string=?)? *(.*)"
|
||||
shellFor s | s `matches` re =
|
||||
case matchRegex re s of
|
||||
Just [flag, shell] -> fromEnvArgs (words shell)
|
||||
_ -> ""
|
||||
shellFor sb =
|
||||
case words sb of
|
||||
[] -> ""
|
||||
[x] -> basename x
|
||||
(first:second:args) | basename first == "busybox" ->
|
||||
case basename second of
|
||||
"sh" -> "ash" -- busybox sh is ash
|
||||
x -> x
|
||||
(first:args) | basename first == "env" ->
|
||||
fromEnvArgs args
|
||||
(first:_) -> basename first
|
||||
|
||||
fromEnvArgs args = fromMaybe "" $ find (notElem '=') $ skipFlags args
|
||||
basename s = reverse . takeWhile (/= '/') . reverse $ s
|
||||
skipFlags = dropWhile ("-" `isPrefixOf`)
|
||||
|
||||
return []
|
||||
runTests = $quickCheckAll
|
||||
|
@@ -196,7 +196,6 @@ nodeChecks = [
|
||||
,checkAssignToSelf
|
||||
,checkEqualsInCommand
|
||||
,checkSecondArgIsComparison
|
||||
,checkComparisonWithLeadingX
|
||||
]
|
||||
|
||||
optionalChecks = map fst optionalTreeChecks
|
||||
@@ -244,6 +243,13 @@ optionalTreeChecks = [
|
||||
cdPositive = "echo $VAR",
|
||||
cdNegative = "VAR=hello; echo $VAR"
|
||||
}, checkUnassignedReferences' True)
|
||||
|
||||
,(newCheckDescription {
|
||||
cdName = "avoid-x-comparisons",
|
||||
cdDescription = "Warn about 'x'-prefix in comparisons",
|
||||
cdPositive = "[ \"x$var\" = xval ]",
|
||||
cdNegative = "[ \"$var\" = val ]"
|
||||
}, nodeChecksToTreeCheck [checkComparisonWithLeadingX])
|
||||
]
|
||||
|
||||
optionalCheckMap :: Map.Map String (Parameters -> Token -> [TokenComment])
|
||||
@@ -584,12 +590,6 @@ prop_checkShebang9 = verifyNotTree checkShebang "# shellcheck shell=sh\ntrue"
|
||||
prop_checkShebang10= verifyNotTree checkShebang "#!foo\n# shellcheck shell=sh ignore=SC2239\ntrue"
|
||||
prop_checkShebang11= verifyTree checkShebang "#!/bin/sh/\ntrue"
|
||||
prop_checkShebang12= verifyTree checkShebang "#!/bin/sh/ -xe\ntrue"
|
||||
prop_checkShebang13= verifyTree checkShebang "#!/bin/busybox sh"
|
||||
prop_checkShebang14= verifyNotTree checkShebang "#!/bin/busybox sh\n# shellcheck shell=sh\n"
|
||||
prop_checkShebang15= verifyNotTree checkShebang "#!/bin/busybox sh\n# shellcheck shell=dash\n"
|
||||
prop_checkShebang16= verifyTree checkShebang "#!/bin/busybox ash"
|
||||
prop_checkShebang17= verifyNotTree checkShebang "#!/bin/busybox ash\n# shellcheck shell=dash\n"
|
||||
prop_checkShebang18= verifyNotTree checkShebang "#!/bin/busybox ash\n# shellcheck shell=sh\n"
|
||||
checkShebang params (T_Annotation _ list t) =
|
||||
if any isOverride list then [] else checkShebang params t
|
||||
where
|
||||
@@ -1015,7 +1015,6 @@ checkSingleQuotedVariables params t@(T_SingleQuoted id s) =
|
||||
,"alias"
|
||||
,"sudo" -- covering "sudo sh" and such
|
||||
,"docker" -- like above
|
||||
,"podman"
|
||||
,"dpkg-query"
|
||||
,"jq" -- could also check that user provides --arg
|
||||
,"rename"
|
||||
@@ -1217,8 +1216,8 @@ checkQuotedCondRegex _ (TC_Binary _ _ "=~" _ rhs) =
|
||||
where
|
||||
error t =
|
||||
unless (isConstantNonRe t) $
|
||||
warn (getId t) 2076
|
||||
"Remove quotes from right-hand side of =~ to match as a regex rather than literally."
|
||||
err (getId t) 2076
|
||||
"Don't quote right-hand side of =~, it'll match literally rather than as a regex."
|
||||
re = mkRegex "[][*.+()|]"
|
||||
hasMetachars s = s `matches` re
|
||||
isConstantNonRe t = fromMaybe False $ do
|
||||
@@ -4000,7 +3999,7 @@ checkComparisonWithLeadingX params t =
|
||||
check lhs rhs
|
||||
_ -> return ()
|
||||
where
|
||||
msg = "Avoid x-prefix in comparisons as it no longer serves a purpose."
|
||||
msg = "Avoid outdated x-prefix in comparisons as it no longer serves a purpose."
|
||||
check lhs rhs = sequence_ $ do
|
||||
l <- fixLeadingX lhs
|
||||
r <- fixLeadingX rhs
|
||||
|
@@ -240,8 +240,6 @@ prop_determineShell7 = determineShellTest "#! /bin/ash" == Dash
|
||||
prop_determineShell8 = determineShellTest' (Just Ksh) "#!/bin/sh" == Sh
|
||||
prop_determineShell9 = determineShellTest "#!/bin/env -S dash -x" == Dash
|
||||
prop_determineShell10 = determineShellTest "#!/bin/env --split-string= dash -x" == Dash
|
||||
prop_determineShell11 = determineShellTest "#!/bin/busybox sh" == Dash -- busybox sh is a specific shell, not posix sh
|
||||
prop_determineShell12 = determineShellTest "#!/bin/busybox ash" == Dash
|
||||
|
||||
determineShellTest = determineShellTest' Nothing
|
||||
determineShellTest' fallbackShell = determineShell fallbackShell . fromJust . prRoot . pScript
|
||||
@@ -255,6 +253,19 @@ determineShell fallbackShell t = fromMaybe Bash $
|
||||
headOrDefault (fromShebang s) [s | ShellOverride s <- annotations]
|
||||
fromShebang (T_Script _ (T_Literal _ s) _) = executableFromShebang s
|
||||
|
||||
-- Given a string like "/bin/bash" or "/usr/bin/env dash",
|
||||
-- return the shell basename like "bash" or "dash"
|
||||
executableFromShebang :: String -> String
|
||||
executableFromShebang = shellFor
|
||||
where
|
||||
shellFor s | "/env " `isInfixOf` s = case matchRegex re s of
|
||||
Just [flag, shell] -> shell
|
||||
_ -> ""
|
||||
shellFor s | ' ' `elem` s = shellFor $ takeWhile (/= ' ') s
|
||||
shellFor s = reverse . takeWhile (/= '/') . reverse $ s
|
||||
re = mkRegex "/env +(-S|--split-string=?)? *([^ ]*)"
|
||||
|
||||
|
||||
-- Given a root node, make a map from Id to parent Token.
|
||||
-- This is used to populate parentMap in Parameters
|
||||
getParentTree :: Token -> Map.Map Id Token
|
||||
|
@@ -1056,7 +1056,7 @@ checkFindRedirections = CommandCheck (Basename "find") f
|
||||
|
||||
prop_checkWhich = verify checkWhich "which '.+'"
|
||||
checkWhich = CommandCheck (Basename "which") $
|
||||
\t -> info (getId $ getCommandTokenOrThis t) 2230 "'which' is non-standard. Use builtin 'command -v' instead."
|
||||
\t -> info (getId $ getCommandTokenOrThis t) 2230 "which is non-standard. Use builtin 'command -v' instead."
|
||||
|
||||
prop_checkSudoRedirect1 = verify checkSudoRedirect "sudo echo 3 > /proc/file"
|
||||
prop_checkSudoRedirect2 = verify checkSudoRedirect "sudo cmd < input"
|
||||
|
@@ -73,15 +73,15 @@ import qualified Data.Map as Map
|
||||
|
||||
|
||||
data SystemInterface m = SystemInterface {
|
||||
-- | Read a file by filename, or return an error
|
||||
-- Read a file by filename, or return an error
|
||||
siReadFile :: String -> m (Either ErrorMessage String),
|
||||
-- | Given:
|
||||
-- Given:
|
||||
-- the current script,
|
||||
-- a list of source-path annotations in effect,
|
||||
-- and a sourced file,
|
||||
-- find the sourced file
|
||||
siFindSource :: String -> [String] -> String -> m FilePath,
|
||||
-- | Get the configuration file (name, contents) for a filename
|
||||
-- Get the configuration file (name, contents) for a filename
|
||||
siGetConfig :: String -> m (Maybe (FilePath, String))
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@
|
||||
module ShellCheck.Parser (parseScript, runTests) where
|
||||
|
||||
import ShellCheck.AST
|
||||
import ShellCheck.ASTLib hiding (runTests)
|
||||
import ShellCheck.ASTLib
|
||||
import ShellCheck.Data
|
||||
import ShellCheck.Interface
|
||||
|
||||
@@ -87,23 +87,11 @@ extglobStart = oneOf extglobStartChars
|
||||
unicodeDoubleQuotes = "\x201C\x201D\x2033\x2036"
|
||||
unicodeSingleQuotes = "\x2018\x2019"
|
||||
|
||||
prop_spacing1 = isOk spacing " \\\n # Comment"
|
||||
prop_spacing2 = isOk spacing "# We can continue lines with \\"
|
||||
prop_spacing3 = isWarning spacing " \\\n # --verbose=true \\"
|
||||
prop_spacing = isOk spacing " \\\n # Comment"
|
||||
spacing = do
|
||||
x <- many (many1 linewhitespace <|> continuation)
|
||||
x <- many (many1 linewhitespace <|> try (string "\\\n" >> return ""))
|
||||
optional readComment
|
||||
return $ concat x
|
||||
where
|
||||
continuation = do
|
||||
try (string "\\\n")
|
||||
-- The line was continued. Warn if this next line is a comment with a trailing \
|
||||
whitespace <- many linewhitespace
|
||||
optional $ do
|
||||
x <- readComment
|
||||
when ("\\" `isSuffixOf` x) $
|
||||
parseProblem ErrorC 1143 "This backslash is part of a comment and does not continue the line."
|
||||
return whitespace
|
||||
|
||||
spacing1 = do
|
||||
spacing <- spacing
|
||||
@@ -1051,7 +1039,6 @@ readComment = do
|
||||
unexpecting "shellcheck annotation" readAnnotationPrefix
|
||||
readAnyComment
|
||||
|
||||
prop_readAnyComment = isOk readAnyComment "# Comment"
|
||||
readAnyComment = do
|
||||
char '#'
|
||||
many $ noneOf "\r\n"
|
||||
@@ -1417,8 +1404,6 @@ readNormalEscaped = called "escaped char" $ do
|
||||
do
|
||||
next <- quotable <|> oneOf "?*@!+[]{}.,~#"
|
||||
when (next == ' ') $ checkTrailingSpaces pos <|> return ()
|
||||
-- Check if this line is followed by a commented line with a trailing backslash
|
||||
when (next == '\n') $ try . lookAhead $ void spacing
|
||||
return $ if next == '\n' then "" else [next]
|
||||
<|>
|
||||
do
|
||||
@@ -3231,8 +3216,8 @@ readScriptFile sourced = do
|
||||
let ignoreShebang = shellAnnotationSpecified || shellFlagSpecified
|
||||
|
||||
unless ignoreShebang $
|
||||
verifyShebang pos (executableFromShebang shebangString)
|
||||
if ignoreShebang || isValidShell (executableFromShebang shebangString) /= Just False
|
||||
verifyShebang pos (getShell shebangString)
|
||||
if ignoreShebang || isValidShell (getShell shebangString) /= Just False
|
||||
then do
|
||||
commands <- withAnnotations annotations readCompoundListOrEmpty
|
||||
id <- endSpan start
|
||||
@@ -3246,6 +3231,17 @@ readScriptFile sourced = do
|
||||
return $ T_Script id shebang []
|
||||
|
||||
where
|
||||
basename s = reverse . takeWhile (/= '/') . reverse $ s
|
||||
skipFlags = dropWhile ("-" `isPrefixOf`)
|
||||
getShell sb =
|
||||
case words sb of
|
||||
[] -> ""
|
||||
[x] -> basename x
|
||||
(first:args) ->
|
||||
if basename first == "env"
|
||||
then fromMaybe "" $ find (notElem '=') $ skipFlags args
|
||||
else basename first
|
||||
|
||||
verifyShebang pos s = do
|
||||
case isValidShell s of
|
||||
Just True -> return ()
|
||||
|
@@ -4,7 +4,6 @@ import Control.Monad
|
||||
import System.Exit
|
||||
import qualified ShellCheck.Analytics
|
||||
import qualified ShellCheck.AnalyzerLib
|
||||
import qualified ShellCheck.ASTLib
|
||||
import qualified ShellCheck.Checker
|
||||
import qualified ShellCheck.Checks.Commands
|
||||
import qualified ShellCheck.Checks.Custom
|
||||
@@ -18,7 +17,6 @@ main = do
|
||||
results <- sequence [
|
||||
ShellCheck.Analytics.runTests
|
||||
,ShellCheck.AnalyzerLib.runTests
|
||||
,ShellCheck.ASTLib.runTests
|
||||
,ShellCheck.Checker.runTests
|
||||
,ShellCheck.Checks.Commands.runTests
|
||||
,ShellCheck.Checks.Custom.runTests
|
||||
|
Reference in New Issue
Block a user