On Fri, Jan 16, 2026 at 10:22:14AM +0100, Michal Privoznik via Devel wrote:
From: Michal Privoznik <[email protected]>

As mentioned in the previous commit, the following function
doesn't echo '1' but '0':

 func() {
     local var=$(false)
     echo $?
 }

It's explained here [1]. Since this kind of error is not easy to
catch a new syntax-check rule is introduced. To avoid having
multiline grep and match only those patterns where '$?' is
examined, let's keep the rule simple and forbid all local
declarations with subshell.

1: https://www.shellcheck.net/wiki/SC2155

Man page of bash(1) and bash_builtins(1) both explain it well, too.

Signed-off-by: Michal Privoznik <[email protected]>
---
build-aux/syntax-check.mk | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
index f605c9b0e3..ff44dfa2fe 100644
--- a/build-aux/syntax-check.mk
+++ b/build-aux/syntax-check.mk
@@ -394,6 +394,12 @@ sc_prohibit_g_autofree_const:
        halt='‘g_autofree’ discards ‘const’ qualifier from pointer target type' 
\
          $(_sc_search_regexp)

+sc_prohibit_local_with_subshell:
+       @prohibit='local [a-zA-Z]+="?\$$\(.+' \

this won't catch variables with underscores etc. in the name, neither
will it catch (if anyone ever touches the script again and does such a
thing) an array initialization, e.g.:

    local domains=( $(run_virsh list --uuid) )

not to mention that there shouldn't be anything than a space before the
`local`, so I'd suggest we instead do something like:

    @prohibit='^ *local .*='

or, if we do want to catch someone using local x=... with TAB for
indentation before the sc_TAB_in_indentation warns them, then:

    @prohibit='^\s*local .*='

and if you want to be super-duper-extra careful, then

    @prohibit='^\s*(local|export|declare|readonly) .*='

+       in_vc_files='\.sh(\.in)?$$' \
+       halt='local variable with subshell does not do what you think it does' \

Well, it does what I think.  Maybe word it differently, like "don't use
that" or "this way you cannot know the exit code" or something.

+         $(_sc_search_regexp)
+

# Many of the function names below came from this filter:
# git grep -B2 '\<_('|grep -E '\.c- *[[:alpha:]_][[:alnum:]_]* ?\(.*[,;]$' \
--
2.52.0

Attachment: signature.asc
Description: PGP signature

Reply via email to