@eslint-sh/eslint-plugin 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -8
- package/dist/command-harvest/builtins/bash.d.ts +1 -1
- package/dist/command-harvest/builtins/bash.js +1 -1
- package/dist/command-harvest/builtins/bats.d.ts +2 -0
- package/dist/command-harvest/builtins/bats.js +3 -0
- package/dist/command-harvest/wrapper-table.d.ts +3 -19
- package/dist/command-harvest/wrapper-table.js +8 -38
- package/dist/configs/bash-3-2.d.ts +7 -6
- package/dist/configs/bash-3-2.js +4 -3
- package/dist/configs/posix-portable.d.ts +1 -1
- package/dist/declaration-conventions/read-declared-commands.d.ts +2 -2
- package/dist/declaration-conventions/read-declared-commands.js +2 -2
- package/dist/eslint-plugin-syntax.d.ts +4 -0
- package/dist/eslint-plugin.d.ts +86 -40
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -2
- package/dist/language/shell-language-options.d.ts +18 -15
- package/dist/language/shell-language-options.js +33 -26
- package/dist/language/shell-language.d.ts +10 -9
- package/dist/language/shell-language.js +18 -35
- package/dist/language/shell-source-code.d.ts +17 -9
- package/dist/language/shell-source-code.js +53 -12
- package/dist/rules/bash-variable-semantics.d.ts +22 -0
- package/dist/rules/bash-variable-semantics.js +41 -0
- package/dist/rules/compat/create-compat-rule.js +1 -1
- package/dist/rules/compat/declaration-options.d.ts +2 -2
- package/dist/rules/compat/declaration-options.js +5 -2
- package/dist/rules/compat/no-append-all-redirect.js +1 -1
- package/dist/rules/compat/no-associative-arrays.js +2 -2
- package/dist/rules/compat/no-brace-sequence-padding-step.js +4 -4
- package/dist/rules/compat/no-case-attributes.js +3 -3
- package/dist/rules/compat/no-case-fallthrough.js +2 -2
- package/dist/rules/compat/no-case-modification.js +2 -2
- package/dist/rules/compat/no-coproc.js +1 -1
- package/dist/rules/compat/no-declare-g.js +3 -3
- package/dist/rules/compat/no-double-bracket.js +2 -2
- package/dist/rules/compat/no-epoch-variables.js +2 -2
- package/dist/rules/compat/no-fd-variable.js +1 -1
- package/dist/rules/compat/no-globstar.js +1 -1
- package/dist/rules/compat/no-lastpipe-semantics.js +2 -2
- package/dist/rules/compat/no-let.js +2 -1
- package/dist/rules/compat/no-mapfile.js +4 -2
- package/dist/rules/compat/no-nameref.js +3 -3
- package/dist/rules/compat/no-negative-array-index.js +39 -9
- package/dist/rules/compat/no-nounset-empty-array.js +15 -4
- package/dist/rules/compat/no-parameter-transformation.js +2 -2
- package/dist/rules/compat/no-pipe-all.js +1 -1
- package/dist/rules/compat/no-printf-time-format.js +4 -2
- package/dist/rules/compat/no-source.js +2 -1
- package/dist/rules/compat/no-test-v.js +4 -2
- package/dist/rules/compat/no-unicode-escape.js +2 -2
- package/dist/rules/compat/no-wait-n.js +4 -2
- package/dist/rules/compat/nounset-array-proof.d.ts +8 -0
- package/dist/rules/compat/nounset-array-proof.js +563 -0
- package/dist/rules/compat/posix-absent-command.d.ts +7 -8
- package/dist/rules/compat/posix-absent-command.js +17 -15
- package/dist/rules/compat/shopt-options.js +3 -1
- package/dist/rules/compat/version-gates.d.ts +9 -9
- package/dist/rules/compat/version-gates.js +13 -13
- package/dist/rules/create-wrapper-rule.js +12 -7
- package/dist/rules/no-dynamic-invocation.d.ts +0 -8
- package/dist/rules/no-dynamic-invocation.js +7 -15
- package/dist/rules/no-eval.js +3 -1
- package/dist/rules/no-masked-exit-status.js +15 -8
- package/dist/rules/no-secret-env-reads.d.ts +4 -3
- package/dist/rules/no-secret-env-reads.js +37 -14
- package/dist/rules/no-secret-flags.d.ts +2 -1
- package/dist/rules/no-secret-flags.js +7 -8
- package/dist/rules/no-unchecked-cd.js +3 -1
- package/dist/rules/no-undeclared-commands.d.ts +1 -15
- package/dist/rules/no-undeclared-commands.js +3 -15
- package/dist/rules/no-unused-declarations.d.ts +1 -18
- package/dist/rules/no-unused-declarations.js +9 -34
- package/dist/rules/prefer-local.js +4 -3
- package/dist/rules/quote-expansions.js +3 -28
- package/dist/rules/require-network-wrapper.d.ts +2 -17
- package/dist/rules/require-network-wrapper.js +33 -4
- package/dist/rules/resolve-declaration-convention.d.ts +5 -6
- package/dist/rules/resolve-declaration-convention.js +5 -6
- package/dist/rules/resolve-network-wrapper.d.ts +19 -0
- package/dist/rules/resolve-network-wrapper.js +57 -26
- package/dist/rules/resolve-transparent-wrappers.d.ts +43 -0
- package/dist/rules/resolve-transparent-wrappers.js +98 -0
- package/dist/rules/set-options.d.ts +2 -1
- package/dist/rules/set-options.js +17 -5
- package/dist/rules/shebang-interpreter.js +4 -2
- package/dist/rules/transparent-wrappers.d.ts +4 -3
- package/dist/rules/transparent-wrappers.js +5 -4
- package/dist/rules/user-pattern.d.ts +5 -3
- package/dist/rules/user-pattern.js +6 -4
- package/dist/syntax/index.d.ts +4 -0
- package/dist/syntax/index.js +4 -0
- package/docs/compat.md +76 -27
- package/docs/custom-rule-tutorial.md +9 -3
- package/docs/examples/no-listed-commands-rule.ts +2 -2
- package/docs/rules/README.md +36 -4
- package/docs/rules/_template.md +2 -2
- package/docs/rules/compat/no-append-all-redirect.md +12 -12
- package/docs/rules/compat/no-associative-arrays.md +14 -14
- package/docs/rules/compat/no-brace-sequence-padding-step.md +12 -12
- package/docs/rules/compat/no-case-attributes.md +13 -13
- package/docs/rules/compat/no-case-fallthrough.md +12 -12
- package/docs/rules/compat/no-case-modification.md +11 -11
- package/docs/rules/compat/no-coproc.md +13 -13
- package/docs/rules/compat/no-declare-g.md +13 -13
- package/docs/rules/compat/no-double-bracket.md +2 -2
- package/docs/rules/compat/no-epoch-variables.md +13 -13
- package/docs/rules/compat/no-fd-variable.md +12 -12
- package/docs/rules/compat/no-globstar.md +13 -13
- package/docs/rules/compat/no-lastpipe-semantics.md +13 -13
- package/docs/rules/compat/no-let.md +2 -2
- package/docs/rules/compat/no-mapfile.md +16 -16
- package/docs/rules/compat/no-nameref.md +13 -13
- package/docs/rules/compat/no-negative-array-index.md +14 -14
- package/docs/rules/compat/no-nounset-empty-array.md +72 -17
- package/docs/rules/compat/no-parameter-transformation.md +19 -19
- package/docs/rules/compat/no-pipe-all.md +13 -13
- package/docs/rules/compat/no-printf-time-format.md +13 -13
- package/docs/rules/compat/no-source.md +2 -2
- package/docs/rules/compat/no-test-v.md +12 -12
- package/docs/rules/compat/no-unicode-escape.md +13 -13
- package/docs/rules/compat/no-wait-n.md +13 -13
- package/docs/rules/no-dynamic-invocation.md +17 -12
- package/docs/rules/no-eval.md +6 -1
- package/docs/rules/no-masked-exit-status.md +4 -0
- package/docs/rules/no-secret-env-reads.md +34 -3
- package/docs/rules/no-secret-flags.md +19 -2
- package/docs/rules/no-unchecked-cd.md +9 -2
- package/docs/rules/no-undeclared-commands.md +16 -15
- package/docs/rules/no-unused-declarations.md +17 -20
- package/docs/rules/prefer-local.md +20 -2
- package/docs/rules/quote-expansions.md +8 -5
- package/docs/rules/require-network-wrapper.md +22 -17
- package/docs/rules/require-shebang.md +10 -4
- package/docs/rules/require-strict-mode.md +6 -0
- package/docs/shellcheck.md +9 -5
- package/docs/transparent-wrappers.md +97 -0
- package/docs/wrapper-rules.md +9 -0
- package/package.json +2 -2
- package/dist/language/end-of-input-marker.d.ts +0 -29
- package/dist/language/end-of-input-marker.js +0 -88
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `sh/compat/no-globstar`
|
|
2
2
|
|
|
3
|
-
Disallow `shopt -s globstar` in scripts
|
|
3
|
+
Disallow `shopt -s globstar` in scripts that must support a shell lacking the option: Bash older than 4.0,
|
|
4
4
|
including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
|
|
5
5
|
|
|
6
6
|
| Configs | Fixable | Languages |
|
|
@@ -18,19 +18,19 @@ The portable alternative is `find`, for example `find dir -name '*.txt'`.
|
|
|
18
18
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
19
19
|
described in [version compatibility](../../compat.md):
|
|
20
20
|
|
|
21
|
-
- `
|
|
22
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
23
|
-
- `dialect: "posix"`: reports
|
|
21
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
22
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
|
|
23
|
+
- `dialect: "posix"`: reports regardless of Bash releases, because POSIX sh has no `shopt`.
|
|
24
24
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
25
25
|
|
|
26
26
|
## Options
|
|
27
27
|
|
|
28
|
-
This rule has no options. Set the
|
|
28
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
29
29
|
|
|
30
30
|
```js
|
|
31
31
|
// eslint.config.js
|
|
32
32
|
{
|
|
33
|
-
languageOptions: { dialect: 'bash',
|
|
33
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
34
34
|
rules: {
|
|
35
35
|
'sh/compat/no-globstar': 'error',
|
|
36
36
|
},
|
|
@@ -41,9 +41,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
41
41
|
|
|
42
42
|
### Incorrect
|
|
43
43
|
|
|
44
|
-
With `
|
|
44
|
+
With `minBashVersion: "3.2"`:
|
|
45
45
|
|
|
46
|
-
<!-- example: {"dialect": "bash", "
|
|
46
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 1} -->
|
|
47
47
|
```sh
|
|
48
48
|
shopt -s nullglob globstar
|
|
49
49
|
for f in src/**/*.sh; do lint "$f"; done
|
|
@@ -51,19 +51,19 @@ for f in src/**/*.sh; do lint "$f"; done
|
|
|
51
51
|
|
|
52
52
|
### Correct
|
|
53
53
|
|
|
54
|
-
With `
|
|
54
|
+
With `minBashVersion: "3.2"`:
|
|
55
55
|
|
|
56
|
-
<!-- example: {"dialect": "bash", "
|
|
56
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
57
57
|
```sh
|
|
58
58
|
find src -name '*.sh' -exec lint {} \;
|
|
59
59
|
shopt -s nullglob
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
With `
|
|
62
|
+
With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, `globstar` is fine.
|
|
63
63
|
|
|
64
64
|
## When not to use it
|
|
65
65
|
|
|
66
|
-
Turn the rule off when your scripts never run on Bash older than 4.0, or leave `
|
|
66
|
+
Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
|
|
67
67
|
unset, which makes the rule report nothing.
|
|
68
68
|
|
|
69
69
|
## Relationship to shellcheck
|
|
@@ -71,4 +71,4 @@ unset, which makes the rule report nothing.
|
|
|
71
71
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
72
72
|
layer. Run shellcheck beside it.
|
|
73
73
|
|
|
74
|
-
shellcheck reports `shopt` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `globstar` for a Bash 3.2
|
|
74
|
+
shellcheck reports `shopt` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `globstar` for a script that must support Bash 3.2. This rule checks that support requirement.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `sh/compat/no-lastpipe-semantics`
|
|
2
2
|
|
|
3
|
-
Disallow `shopt -s lastpipe` in scripts
|
|
3
|
+
Disallow `shopt -s lastpipe` in scripts that must support a shell lacking the option: Bash older than 4.2,
|
|
4
4
|
including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
|
|
5
5
|
|
|
6
6
|
| Configs | Fixable | Languages |
|
|
@@ -18,19 +18,19 @@ The portable alternative is process substitution: `while read -r line; do …; d
|
|
|
18
18
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
19
19
|
described in [version compatibility](../../compat.md):
|
|
20
20
|
|
|
21
|
-
- `
|
|
22
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
23
|
-
- `dialect: "posix"`: reports
|
|
21
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
22
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.2`.
|
|
23
|
+
- `dialect: "posix"`: reports regardless of Bash releases.
|
|
24
24
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
25
25
|
|
|
26
26
|
## Options
|
|
27
27
|
|
|
28
|
-
This rule has no options. Set the
|
|
28
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
29
29
|
|
|
30
30
|
```js
|
|
31
31
|
// eslint.config.js
|
|
32
32
|
{
|
|
33
|
-
languageOptions: { dialect: 'bash',
|
|
33
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
34
34
|
rules: {
|
|
35
35
|
'sh/compat/no-lastpipe-semantics': 'error',
|
|
36
36
|
},
|
|
@@ -41,9 +41,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
41
41
|
|
|
42
42
|
### Incorrect
|
|
43
43
|
|
|
44
|
-
With `
|
|
44
|
+
With `minBashVersion: "3.2"`:
|
|
45
45
|
|
|
46
|
-
<!-- example: {"dialect": "bash", "
|
|
46
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 1} -->
|
|
47
47
|
```sh
|
|
48
48
|
shopt -s lastpipe
|
|
49
49
|
cmd | while read -r line; do total=$line; done
|
|
@@ -51,23 +51,23 @@ cmd | while read -r line; do total=$line; done
|
|
|
51
51
|
|
|
52
52
|
### Correct
|
|
53
53
|
|
|
54
|
-
With `
|
|
54
|
+
With `minBashVersion: "3.2"`:
|
|
55
55
|
|
|
56
|
-
<!-- example: {"dialect": "bash", "
|
|
56
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
57
57
|
```sh
|
|
58
58
|
while read -r line; do total=$line; done < <(cmd)
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
With `
|
|
61
|
+
With `minBashVersion: "4.2"` or newer, or with no `minBashVersion`, the original forms are fine.
|
|
62
62
|
|
|
63
63
|
## When not to use it
|
|
64
64
|
|
|
65
65
|
Turn the rule off when your scripts never run on Bash older than 4.2, or leave
|
|
66
|
-
`
|
|
66
|
+
`minBashVersion` unset, which makes the rule report nothing.
|
|
67
67
|
|
|
68
68
|
## Relationship to shellcheck
|
|
69
69
|
|
|
70
70
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
71
71
|
layer. Run shellcheck beside it.
|
|
72
72
|
|
|
73
|
-
shellcheck warns that variables assigned in the last pipeline element are lost (SC2030/SC2031), and understands `shopt -s lastpipe` for that purpose, but it cannot
|
|
73
|
+
shellcheck warns that variables assigned in the last pipeline element are lost (SC2030/SC2031), and understands `shopt -s lastpipe` for that purpose, but it cannot check support for a minimum Bash version, so it cannot report the option for a script that must support Bash 3.2. This rule checks that support requirement.
|
|
@@ -27,12 +27,12 @@ The portable alternative is arithmetic expansion, `n=$((1 + 2))`. The rule offer
|
|
|
27
27
|
|
|
28
28
|
This is a POSIX-only gate. Every Bash has `let`, so whether the rule reports depends only on `dialect`, as described in [version compatibility](../../compat.md):
|
|
29
29
|
|
|
30
|
-
- `dialect: "posix"`: reports
|
|
30
|
+
- `dialect: "posix"`: reports regardless of Bash releases.
|
|
31
31
|
- `dialect: "bash"` (the default), `"bats"`, `"mksh"` or `"zsh"`: never reports.
|
|
32
32
|
|
|
33
33
|
## Options
|
|
34
34
|
|
|
35
|
-
This rule has no options. Set the
|
|
35
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
36
36
|
|
|
37
37
|
```js
|
|
38
38
|
// eslint.config.js
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `sh/compat/no-mapfile`
|
|
2
2
|
|
|
3
|
-
Disallow the `mapfile` builtin and its synonym `readarray` in scripts
|
|
3
|
+
Disallow the `mapfile` builtin and its synonym `readarray` in scripts that must support a shell lacking
|
|
4
4
|
them: Bash older than 4.0, including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
|
|
5
5
|
|
|
6
6
|
| Configs | Fixable | Languages |
|
|
@@ -16,9 +16,9 @@ never filled.
|
|
|
16
16
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
17
17
|
described in [version compatibility](../../compat.md):
|
|
18
18
|
|
|
19
|
-
- `
|
|
20
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
21
|
-
- `dialect: "posix"`: reports
|
|
19
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
20
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
|
|
21
|
+
- `dialect: "posix"`: reports regardless of Bash releases.
|
|
22
22
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
23
23
|
|
|
24
24
|
The rule reports every command whose effective command is `mapfile` or `readarray`, after
|
|
@@ -31,7 +31,7 @@ For `mapfile -t NAME` or `readarray -t NAME`, written directly (no wrapper and n
|
|
|
31
31
|
`VAR=value`) in a Bash or Bats file, the rule suggests a `while IFS= read -r` loop that fills
|
|
32
32
|
the same array the same way:
|
|
33
33
|
|
|
34
|
-
<!-- transform: {"kind": "suggestion", "dialect": "bash", "
|
|
34
|
+
<!-- transform: {"kind": "suggestion", "dialect": "bash", "minBashVersion": "3.2"} -->
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
37
|
mapfile -t lines < in.txt
|
|
@@ -57,12 +57,12 @@ assignment, a wrapper, and every file under `dialect: "posix"`.
|
|
|
57
57
|
|
|
58
58
|
## Options
|
|
59
59
|
|
|
60
|
-
This rule has no options. Set the
|
|
60
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
61
61
|
|
|
62
62
|
```js
|
|
63
63
|
// eslint.config.js
|
|
64
64
|
{
|
|
65
|
-
languageOptions: { dialect: 'bash',
|
|
65
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
66
66
|
rules: {
|
|
67
67
|
'sh/compat/no-mapfile': 'error',
|
|
68
68
|
},
|
|
@@ -73,9 +73,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
73
73
|
|
|
74
74
|
### Incorrect
|
|
75
75
|
|
|
76
|
-
With `
|
|
76
|
+
With `minBashVersion: "3.2"`:
|
|
77
77
|
|
|
78
|
-
<!-- example: {"dialect": "bash", "
|
|
78
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 3} -->
|
|
79
79
|
```sh
|
|
80
80
|
mapfile -t lines < in.txt # mapfile needs Bash 4.0
|
|
81
81
|
git ls-files | readarray -t files # readarray is the same builtin
|
|
@@ -84,9 +84,9 @@ command mapfile -t lines < in.txt # reached through the command wrapper
|
|
|
84
84
|
|
|
85
85
|
### Correct
|
|
86
86
|
|
|
87
|
-
With `
|
|
87
|
+
With `minBashVersion: "3.2"`:
|
|
88
88
|
|
|
89
|
-
<!-- example: {"dialect": "bash", "
|
|
89
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
90
90
|
```sh
|
|
91
91
|
{ lines=(); while IFS= read -r || [ -n "$REPLY" ]; do lines+=("$REPLY"); done; } < in.txt
|
|
92
92
|
|
|
@@ -95,16 +95,16 @@ while IFS= read -r line; do
|
|
|
95
95
|
done < in.txt
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
With `
|
|
98
|
+
With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`:
|
|
99
99
|
|
|
100
|
-
<!-- example: {"dialect": "bash", "
|
|
100
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "4.0"} -->
|
|
101
101
|
```sh
|
|
102
102
|
mapfile -t lines < in.txt
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
## When not to use it
|
|
106
106
|
|
|
107
|
-
Turn the rule off when your scripts never run on Bash older than 4.0, or leave `
|
|
107
|
+
Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
|
|
108
108
|
unset, which makes the rule report nothing.
|
|
109
109
|
|
|
110
110
|
## Relationship to shellcheck
|
|
@@ -113,6 +113,6 @@ eslint-sh is a convention and contract linter: a policy layer, where shellcheck
|
|
|
113
113
|
layer. Run shellcheck beside it.
|
|
114
114
|
|
|
115
115
|
shellcheck reports Bash-only features in scripts it treats as POSIX sh (the SC3xxx checks), but
|
|
116
|
-
it cannot
|
|
116
|
+
it cannot check support for a minimum Bash version, so it cannot report `mapfile` in a script that must run on
|
|
117
117
|
Bash 3.2. shellcheck 0.11.0 does recommend `mapfile` or `read -a` over `a=($(cmd))` splitting (SC2207) under `-s bash`, which is
|
|
118
|
-
the opposite advice for a Bash 3.2
|
|
118
|
+
the opposite advice for a script that must support Bash 3.2. This rule checks that support requirement.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `sh/compat/no-nameref`
|
|
2
2
|
|
|
3
|
-
Disallow namerefs (`declare -n`, `typeset -n`, `local -n`) in scripts
|
|
3
|
+
Disallow namerefs (`declare -n`, `typeset -n`, `local -n`) in scripts that must support a shell lacking
|
|
4
4
|
them: Bash older than 4.3, including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
|
|
5
5
|
|
|
6
6
|
| Configs | Fixable | Languages |
|
|
@@ -18,19 +18,19 @@ The portable alternative is to pass the variable's name and use it directly. On
|
|
|
18
18
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
19
19
|
described in [version compatibility](../../compat.md):
|
|
20
20
|
|
|
21
|
-
- `
|
|
22
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
23
|
-
- `dialect: "posix"`: reports
|
|
21
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
22
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.3`.
|
|
23
|
+
- `dialect: "posix"`: reports regardless of Bash releases, with the `eval` advice.
|
|
24
24
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
25
25
|
|
|
26
26
|
## Options
|
|
27
27
|
|
|
28
|
-
This rule has no options. Set the
|
|
28
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
29
29
|
|
|
30
30
|
```js
|
|
31
31
|
// eslint.config.js
|
|
32
32
|
{
|
|
33
|
-
languageOptions: { dialect: 'bash',
|
|
33
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
34
34
|
rules: {
|
|
35
35
|
'sh/compat/no-nameref': 'error',
|
|
36
36
|
},
|
|
@@ -41,9 +41,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
41
41
|
|
|
42
42
|
### Incorrect
|
|
43
43
|
|
|
44
|
-
With `
|
|
44
|
+
With `minBashVersion: "3.2"`:
|
|
45
45
|
|
|
46
|
-
<!-- example: {"dialect": "bash", "
|
|
46
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
|
|
47
47
|
```sh
|
|
48
48
|
set_result() {
|
|
49
49
|
local -n out=$1
|
|
@@ -54,9 +54,9 @@ declare -n alias=target
|
|
|
54
54
|
|
|
55
55
|
### Correct
|
|
56
56
|
|
|
57
|
-
With `
|
|
57
|
+
With `minBashVersion: "3.2"`:
|
|
58
58
|
|
|
59
|
-
<!-- example: {"dialect": "bash", "
|
|
59
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
60
60
|
```sh
|
|
61
61
|
set_result() {
|
|
62
62
|
printf -v "$1" '%s' done
|
|
@@ -66,11 +66,11 @@ read_by_name() {
|
|
|
66
66
|
}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
With `
|
|
69
|
+
With `minBashVersion: "4.3"` or newer, or with no `minBashVersion`, namerefs are fine.
|
|
70
70
|
|
|
71
71
|
## When not to use it
|
|
72
72
|
|
|
73
|
-
Turn the rule off when your scripts never run on Bash older than 4.3, or leave `
|
|
73
|
+
Turn the rule off when your scripts never run on Bash older than 4.3, or leave `minBashVersion`
|
|
74
74
|
unset, which makes the rule report nothing.
|
|
75
75
|
|
|
76
76
|
## Relationship to shellcheck
|
|
@@ -78,4 +78,4 @@ unset, which makes the rule report nothing.
|
|
|
78
78
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
79
79
|
layer. Run shellcheck beside it.
|
|
80
80
|
|
|
81
|
-
Under `-s sh`, shellcheck 0.11.0 reports the command, not the option: `local -n` draws SC3043 (`local` is undefined in POSIX sh), and `declare -n` and `typeset -n` draw SC3044. Under `-s bash` it reports nothing for a nameref. It does not know which Bash release a script must run on, so it reports nothing for a nameref in a Bash 4.2 or 3.2
|
|
81
|
+
Under `-s sh`, shellcheck 0.11.0 reports the command, not the option: `local -n` draws SC3043 (`local` is undefined in POSIX sh), and `declare -n` and `typeset -n` draw SC3044. Under `-s bash` it reports nothing for a nameref. It does not know which Bash release a script must run on, so it reports nothing for a nameref in a script that must support Bash 4.2 or 3.2. This rule checks that support requirement.
|
|
@@ -10,15 +10,15 @@ whose target shell lacks them: Bash older than 4.3, including the Bash 3.2 that
|
|
|
10
10
|
|
|
11
11
|
## Rule details
|
|
12
12
|
|
|
13
|
-
Negative subscripts count back from the end of an indexed array. Bash NEWS for 4.3 introduces assigning, referencing and unsetting elements this way; Bash 4.2 already reads `${arr[-1]}`, but rejects the element length `${#arr[-1]}`, assigning and unsetting with `bad array subscript` (see the [evidence table](../../compat.md#evidence)). The rule uses 4.3, the first release where every use works, so a plain `${arr[-1]}` read at `
|
|
13
|
+
Negative subscripts count back from the end of an indexed array. Bash NEWS for 4.3 introduces assigning, referencing and unsetting elements this way; Bash 4.2 already reads `${arr[-1]}`, but rejects the element length `${#arr[-1]}`, assigning and unsetting with `bad array subscript` (see the [evidence table](../../compat.md#evidence)). The rule uses 4.3, the first release where every use works, so a plain `${arr[-1]}` read at `minBashVersion: "4.2"` is reported although 4.2 accepts it. Bash 3.2 fails with `bad array subscript`.
|
|
14
14
|
|
|
15
|
-
The rule reports a subscript that is a minus sign followed by a static decimal
|
|
15
|
+
The rule reports a subscript that is a minus sign followed by a nonzero static integer (decimal, octal, hexadecimal, or Bash `base#digits` for bases 2–64), on an expansion (`${arr[-1]}`, `${#arr[-1]}`) or on an assignment (`arr[-1]=x`). It also reports unsetting an element, `unset arr[-1]` (quoted or not, also after options such as `-v` and after `--`), which Bash NEWS for 4.3 covers; that form has no suggestion. It does not evaluate arithmetic expressions or machine-integer overflow. Invalid integer spellings such as `08`, `2#2`, or a leading-zero base prefix (`02#1`, `08#1`) are not evidence of a negative index. It does not report zero in any base (`-0`, `-00`, `-0x0`, `-2#0`, which Bash 3.2 accepts), `${v: -1}` (a substring offset, not a subscript), a computed `-$n`, or a parenthesized `-(1)`. An associative array's `-1` key is a plain string; the rule cannot tell and reports it, but associative arrays need Bash 4.0 anyway.
|
|
16
16
|
|
|
17
17
|
### Suggestion
|
|
18
18
|
|
|
19
19
|
For a bare `${NAME[-N]}` read, the rule suggests counting from the length:
|
|
20
20
|
|
|
21
|
-
<!-- transform: {"kind": "suggestion", "dialect": "bash", "
|
|
21
|
+
<!-- transform: {"kind": "suggestion", "dialect": "bash", "minBashVersion": "3.2"} -->
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
24
|
echo "${arr[-1]}"
|
|
@@ -31,19 +31,19 @@ Negative subscripts count back from the highest assigned index plus one, while `
|
|
|
31
31
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
32
32
|
described in [version compatibility](../../compat.md):
|
|
33
33
|
|
|
34
|
-
- `
|
|
35
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
34
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
35
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.3`.
|
|
36
36
|
- `dialect: "posix"`: reports nothing in practice, because POSIX sh has no arrays, because the POSIX parser rejects it with a parse error before any rule runs.
|
|
37
37
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
38
38
|
|
|
39
39
|
## Options
|
|
40
40
|
|
|
41
|
-
This rule has no options. Set the
|
|
41
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
42
42
|
|
|
43
43
|
```js
|
|
44
44
|
// eslint.config.js
|
|
45
45
|
{
|
|
46
|
-
languageOptions: { dialect: 'bash',
|
|
46
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
47
47
|
rules: {
|
|
48
48
|
'sh/compat/no-negative-array-index': 'error',
|
|
49
49
|
},
|
|
@@ -54,9 +54,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
54
54
|
|
|
55
55
|
### Incorrect
|
|
56
56
|
|
|
57
|
-
With `
|
|
57
|
+
With `minBashVersion: "3.2"`:
|
|
58
58
|
|
|
59
|
-
<!-- example: {"dialect": "bash", "
|
|
59
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
|
|
60
60
|
```sh
|
|
61
61
|
last=${items[-1]}
|
|
62
62
|
items[-1]=done
|
|
@@ -64,24 +64,24 @@ items[-1]=done
|
|
|
64
64
|
|
|
65
65
|
### Correct
|
|
66
66
|
|
|
67
|
-
With `
|
|
67
|
+
With `minBashVersion: "3.2"`:
|
|
68
68
|
|
|
69
|
-
<!-- example: {"dialect": "bash", "
|
|
69
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
70
70
|
```sh
|
|
71
71
|
last=${items[$((${#items[@]}-1))]}
|
|
72
72
|
items[$((${#items[@]}-1))]=done
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
With `
|
|
75
|
+
With `minBashVersion: "4.3"` or newer, or with no `minBashVersion`, the original forms are fine.
|
|
76
76
|
|
|
77
77
|
## When not to use it
|
|
78
78
|
|
|
79
79
|
Turn the rule off when your scripts never run on Bash older than 4.3, or leave
|
|
80
|
-
`
|
|
80
|
+
`minBashVersion` unset, which makes the rule report nothing.
|
|
81
81
|
|
|
82
82
|
## Relationship to shellcheck
|
|
83
83
|
|
|
84
84
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
85
85
|
layer. Run shellcheck beside it.
|
|
86
86
|
|
|
87
|
-
shellcheck reports negative array subscripts in scripts it treats as POSIX sh (SC3054), but it cannot
|
|
87
|
+
shellcheck reports negative array subscripts in scripts it treats as POSIX sh (SC3054), but it cannot check support for a minimum Bash version, so it cannot report `${arr[-1]}` for a script that must support Bash 3.2. This rule checks that support requirement.
|
|
@@ -6,18 +6,33 @@ ships as `/bin/bash`.
|
|
|
6
6
|
|
|
7
7
|
| Configs | Fixable | Languages |
|
|
8
8
|
| ------- | ------- | --------- |
|
|
9
|
-
| `
|
|
9
|
+
| `posix-portable` | suggestions | `sh/sh` |
|
|
10
10
|
|
|
11
11
|
## Rule details
|
|
12
12
|
|
|
13
13
|
The syntax is in every Bash, but through Bash 4.3, expanding an empty array while `nounset` is on aborts the script with `a[@]: unbound variable`. Bash 4.4 is the first release where it expands to nothing. This is the classic "works on Linux CI, breaks on a Mac" failure: a script that runs under `set -euo pipefail` and passes an optional, possibly empty, argument array dies on macOS `/bin/bash`.
|
|
14
14
|
|
|
15
|
-
The rule
|
|
15
|
+
The rule considers an expansion when both of these hold:
|
|
16
16
|
|
|
17
|
-
- the file turns `nounset` on somewhere: a `set` command that enables it (`set -u`, `set -eu`, `set -o nounset`), or a shebang that passes the flag (`#!/bin/bash -eu`, or `#!/usr/bin/env -S bash -eu`).
|
|
17
|
+
- the file turns `nounset` on somewhere: a `set` command that enables it (`set -u`, `set -eu`, `set -o nounset`), or a shebang that passes the flag (`#!/bin/bash -eu`, or `#!/usr/bin/env -S bash -eu`). This is the conservative starting point because a function defined before `set -u` can run after it;
|
|
18
18
|
- an expansion is `${name[@]}` or `${name[*]}` with no operator, in quotes or not.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
The rule suppresses a report only when a narrow local proof establishes safety:
|
|
21
|
+
|
|
22
|
+
- a preceding static `set +u` or `set +o nounset` leaves nounset off;
|
|
23
|
+
- an ordinary assignment such as `a=(x)` or `a=("")` guarantees a member. `FUNCNAME` is excluded because it does not obey ordinary assignment semantics. Every element must be a static word; quoted empty strings count, while computed words and unquoted globs do not;
|
|
24
|
+
- `[ "${#a[@]}" -eq 0 ] && return` exits the current function on the empty path, or the same zero-length check uses `exit`. `test` and `[[ ... ]]` spellings are also recognized. With `[` or `test`, the length operand must be an ordinary double-quoted word: unquoted counts can split under a changed `IFS`, making the test fail without proving the array non-empty. An optional literal numeric return/exit status is allowed;
|
|
25
|
+
- the expansion is in the then arm of a single positive length test: `[ "${#a[@]}" -gt 0 ]`, `[[ ${#a[@]} -ne 0 ]]`, or `(( ${#a[@]} ))`, for example.
|
|
26
|
+
|
|
27
|
+
Facts stay in one sequential statement list. A simple assignment invalidates the fact for its target, so `a=(x); a=()` still reports. Static `set` commands apply option changes in order, so re-enabling nounset removes the off proof. Other calls, including function calls, `unset`, and `shopt`, and compound statements discard facts. Assignments and option changes in a function, loop, branch, or subshell do not establish facts in the surrounding list. A loop's word list can use facts from immediately before the loop; its body starts afresh. Redirections, background statements, prefix assignments on the expanding command, arithmetic expansions, indirect expansions, localized strings, or other potentially mutating argument expansions prevent a proof.
|
|
28
|
+
|
|
29
|
+
A top-level `return` is not an exit proof: when the script is executed rather than sourced, Bash rejects it and continues to the expansion. For example, `set -u; a=(); [ "${#a[@]}" -eq 0 ] && return; echo "${a[@]}"` still reports. Put that guard inside a function or use `exit` when the intended behavior is to exit the script.
|
|
30
|
+
|
|
31
|
+
The rule does not interpret function bodies at call sites, follow sourced files, or prove data returned by other commands. Dynamic command names, actual calls to `eval`, `source`, `.`, `trap`, `alias`, `unalias`, `enable`, `fc`, `read`, `mapfile`, `readarray`, `getopts`, `unset`, or `let`, indirect expansions (including key/name forms), localized strings, writes or `for`/`select` bindings to special `BASH_*` variables, the executable `PS4` trace prefix, or writable intrinsic integers (`OPTIND`, `RANDOM`, `SECONDS`), definitions overriding proof builtins, function names outside plain shell identifiers, and unrecognized wrapper flags disable local proofs for the file, including when reached through `builtin` or `command` wrappers. Wrapped declaration commands, and declarations using readonly, integer, associative-array or reference attributes or unmodeled arguments, disable local proofs for the file. A reference or integer variable can write interpreter arrays indirectly, so a later `set +u` is not trusted either. Ordinary `local a` and `local -a a` declarations do not block a subsequent literal assignment proof. Unmodeled arithmetic (including numeric `[[ ... ]]` operands, array indices, slices and `let`), `[[ -v ... ]]`, and coprocesses also disable local proofs because they can evaluate variable text or change special arrays. Direct array lengths and literal nonnegative integers remain supported in arithmetic tests. A `printf` call is considered inert only with a static format made of literal text, `%%`, and the simple string conversions `%s`, `%b`, `%q`, or `%c`; `-v` requires a plain ordinary variable name. Other formats, interpreter-backed or unknown destinations and `%n` can write interpreter state, so they disable local proofs, including through wrappers. Command-based `[` and `test` forms require fixed non-name-lookup operators and operands known to be one word (static or a single double-quoted scalar word). `-v`/`-R`, unknown operators, multiword expansions and unmodeled compound tests disable local proofs: their argument parsing can reach arithmetic variable-name evaluation. These restrictions avoid trusting an assignment that can fail, write through a reference, or run under changed interpreter behavior. Ordinary builtin behavior and ordinary variables are assumed when the file contains no evidence to the contrary; this is not a model of arbitrary startup or sourced-caller state.
|
|
32
|
+
|
|
33
|
+
Consequently, guarded code can still report where the proof would require another execution path, an intervening call, a caller contract, or one of the excluded constructs. The message says the expansion is not proven safe and remains conditional on the array actually being empty and nounset being on.
|
|
34
|
+
|
|
35
|
+
These forms work on an empty array under `set -u` in every Bash, and are not reported: `${#a[@]}`, `${!a[@]}`, `${a[@]-default}`, and the guarded forms below, including an expansion inside `${a[@]+…}` or `${a[@]:+…}` of the same array. The slice `${a[@]:1}` and the replacement `${a[@]/x/y}` were observed to work on Bash 3.2 to 4.1 and fail only on 4.2 and 4.3, which a minimum-version gate cannot express, so they are not reported either.
|
|
21
36
|
|
|
22
37
|
The rule offers a guarded spelling as a suggestion when the word is exactly the quoted expansion:
|
|
23
38
|
|
|
@@ -29,15 +44,15 @@ An unquoted expansion, or one inside a longer word, reports with no suggestion.
|
|
|
29
44
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
30
45
|
described in [version compatibility](../../compat.md):
|
|
31
46
|
|
|
32
|
-
- `
|
|
33
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
47
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
48
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.4`.
|
|
34
49
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
35
50
|
|
|
36
51
|
### Suggestion
|
|
37
52
|
|
|
38
53
|
A suggestion rewrites the quoted `[@]` form:
|
|
39
54
|
|
|
40
|
-
<!-- transform: {"kind": "suggestion", "dialect": "bash", "
|
|
55
|
+
<!-- transform: {"kind": "suggestion", "dialect": "bash", "minBashVersion": "3.2"} -->
|
|
41
56
|
```sh
|
|
42
57
|
set -u
|
|
43
58
|
run_tool "${extra[@]}"
|
|
@@ -48,25 +63,37 @@ run_tool ${extra[@]+"${extra[@]}"}
|
|
|
48
63
|
|
|
49
64
|
## Options
|
|
50
65
|
|
|
51
|
-
This rule has no options.
|
|
66
|
+
This rule has no options. It is an explicit opt-in for `bash-3.2`. Enable it when a script
|
|
67
|
+
runs with `set -u` on Bash below 4.4 and its arrays can really be empty. Its local proofs
|
|
68
|
+
cannot establish every caller or helper contract, so scripts whose arrays are always non-empty
|
|
69
|
+
can still produce noise. `posix-portable` continues to enable it.
|
|
70
|
+
|
|
71
|
+
Extend the preset and enable the rule explicitly:
|
|
52
72
|
|
|
53
73
|
```js
|
|
54
74
|
// eslint.config.js
|
|
55
|
-
{
|
|
56
|
-
|
|
75
|
+
import { defineConfig } from 'eslint/config';
|
|
76
|
+
import sh from '@eslint-sh/eslint-plugin';
|
|
77
|
+
|
|
78
|
+
export default defineConfig({
|
|
79
|
+
files: ['**/*.sh'],
|
|
80
|
+
extends: [sh.configs['bash-3.2']],
|
|
57
81
|
rules: {
|
|
58
82
|
'sh/compat/no-nounset-empty-array': 'error',
|
|
59
83
|
},
|
|
60
|
-
}
|
|
84
|
+
});
|
|
61
85
|
```
|
|
62
86
|
|
|
87
|
+
For another target, set `languageOptions.minBashVersion` explicitly. The rule reports only below
|
|
88
|
+
Bash 4.4; enabling it does not change that boundary.
|
|
89
|
+
|
|
63
90
|
## Examples
|
|
64
91
|
|
|
65
92
|
### Incorrect
|
|
66
93
|
|
|
67
|
-
With `
|
|
94
|
+
With `minBashVersion: "3.2"`:
|
|
68
95
|
|
|
69
|
-
<!-- example: {"dialect": "bash", "
|
|
96
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
|
|
70
97
|
```sh
|
|
71
98
|
set -euo pipefail
|
|
72
99
|
extra=()
|
|
@@ -76,9 +103,9 @@ echo "args: ${extra[*]}"
|
|
|
76
103
|
|
|
77
104
|
### Correct
|
|
78
105
|
|
|
79
|
-
With `
|
|
106
|
+
With `minBashVersion: "3.2"`:
|
|
80
107
|
|
|
81
|
-
<!-- example: {"dialect": "bash", "
|
|
108
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
82
109
|
```sh
|
|
83
110
|
set -euo pipefail
|
|
84
111
|
extra=()
|
|
@@ -87,12 +114,40 @@ echo "args: ${extra[*]-}"
|
|
|
87
114
|
echo "count: ${#extra[@]}"
|
|
88
115
|
```
|
|
89
116
|
|
|
90
|
-
|
|
117
|
+
Local proofs also allow these forms with `minBashVersion: "3.2"`:
|
|
118
|
+
|
|
119
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
120
|
+
```sh
|
|
121
|
+
set -u
|
|
122
|
+
extra=(--verbose)
|
|
123
|
+
run_tool "${extra[@]}"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
127
|
+
```sh
|
|
128
|
+
set -u
|
|
129
|
+
set +u
|
|
130
|
+
extra=()
|
|
131
|
+
run_tool "${extra[@]}"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
135
|
+
```sh
|
|
136
|
+
run_optional() {
|
|
137
|
+
set -u
|
|
138
|
+
extra=()
|
|
139
|
+
[ "${#extra[@]}" -eq 0 ] && return
|
|
140
|
+
run_tool "${extra[@]}"
|
|
141
|
+
}
|
|
142
|
+
run_optional
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
With `minBashVersion: "4.4"` or newer, with no `minBashVersion`, or in a file that never turns on
|
|
91
146
|
`set -u`, whole-array expansions are fine.
|
|
92
147
|
|
|
93
148
|
## When not to use it
|
|
94
149
|
|
|
95
|
-
Turn the rule off when your scripts never run on Bash older than 4.4, or leave `
|
|
150
|
+
Turn the rule off when your scripts never run on Bash older than 4.4, or leave `minBashVersion`
|
|
96
151
|
unset, which makes the rule report nothing.
|
|
97
152
|
|
|
98
153
|
## Relationship to shellcheck
|