[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] Shell scripting bafflement
From: |
Greg Chicares |
Subject: |
Re: [lmi] Shell scripting bafflement |
Date: |
Thu, 27 Feb 2020 23:13:58 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.4.1 |
On 2020-02-27 02:38, Vadim Zeitlin wrote:
> On Thu, 27 Feb 2020 00:34:01 +0000 Greg Chicares <address@hidden> wrote:
[...]
> GC> Consider the following commands, which
> GC> - test a resolvable URL vs. one spoiled by adding 'X' after "https://"
> GC> - with vs. without "$()"
> GC>
> GC> $if curl https://Xgit.savannah.nongnu.org:443 >/dev/null 2>&1; then echo
> true; else echo false; fi
> GC> false
> GC> $if curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1; then echo
> true; else echo false; fi
> GC> true
> GC>
> GC> $if $(curl https://Xgit.savannah.nongnu.org:443 >/dev/null 2>&1); then
> echo true; else echo false; fi
> GC> false
> GC> $if $(curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1); then
> echo true; else echo false; fi
> GC> true
> GC>
> GC> The effects seem to be the same with or without "$()", so what does the
> GC> the "$()" do in this case? And why does it seem to make no difference?
>
> The difference is that you don't use "[" at all here.
Okay, yes, that explains the difference between
if [ command ]
and
if [ $(command) ]
, but I'd like to ask a different question: what's the difference between
if $(curl some_URL >/dev/null 2>&1)
and
if curl some_URL >/dev/null 2>&1
? In the examples quoted above, they appear to behave identically. I found
that surprising. I understand that in
if curl some_URL >/dev/null 2>&1
the command's return code is 0 or not depending on the URL's reachability.
However, here:
if $(curl some_URL >/dev/null 2>&1)
I was expecting that
- the command would be run in a subshell
- the command's return code would vanish when that subshell returns
- the command-expansion's return code would be 0 if the subshell
executed the command
but it seems that the command-expansion's return code is the
command's return code. The bash manual prescribes that:
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Simple-Command-Expansion
| If one of the expansions contained a command substitution, the
| exit status of the command is the exit status of the last
| command substitution performed.
but AFAICT POSIX doesn't specify anything:
https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03
> What can I say, nobody ever pretended shell wasn't confusing. IMHO this is
> not the worst part, because typically once you realize the difference
> between "if command" and "if test condition", things should be relatively
> clear.
Yeah. Some languages were designed, and show a coherent set of design
principles. OTOH, other languages (e.g., the shell grammar) have evolved,
like a natural human language.
> The best advice I can give about shell scripting is to always test
> anything you might have a doubt about in a separate snippet to ensure that
> it behaves as you expect it to, because failures in the actual scripts are
> hard to debug and often lead to unforeseeable weirdness later on.
That's how I came up with this test:
if [ "$(umask)" -ne 022 ]; then
in lmi commit 135b344eb6d. I always have to look up the syntax for
comparisons like that. (Using 'shellcheck' helps, too.)