lmi
[Top][All Lists]
Advanced

[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 00:34:01 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.4.1

On 2020-02-26 22:37, Vadim Zeitlin wrote:
> On Wed, 26 Feb 2020 22:27:11 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> Vadim--Sorry to bother you with this, but I just can't see why
> GC> these two nearly-identical commands behave oppositely, and I'm
> GC> sure you'll know why.
> 
>  I think I do, but I feel like I'm missing something crucial here: why do
> you say that these commands are nearly-identical when it looks to me that
> they're not identical at all?

That's because you understand what they mean. To me, they're more like
abstract strings of symbols. Evidently
  s/cmd/[ $(&) ]/
does make a difference in practice, yet I anticipated that $() and [] would
be nilpotent--and, specifically, that I could take a valid conditional like
  if [ "$(id -u)" -eq 0 ]; then ...
and replace everything within "[]" with some command to produce another
valid conditional. But already I lead myself astray, because I think of that
as similar to a C++ construct like
  if(true == some_boolean_function())
which is trivially the same as
  if(some_boolean_function())
yet the following two shell constructs are not the same:

  if [ "$(id -u)" -ne 0 ] ; then echo true; else echo false; fi
  if [ "$(id -u)" ] ; then echo true; else echo false; fi

because the former prints "true" iff I am not root, but the latter
prints "true" whether or not I am root. Let me try to explain that
in light of what else you said...

> GC> But if I enclose the command in "[ $(...) ]", it "fails":
> 
>  This tests... nothing. $(...) expands to nothing because there is no
> output of curl, as you had taken care to suppress it, and so this is
> equivalent to "[ ]". To be honest, I didn't know what does testing nothing
> does, but it turns out that it always returns false.

This:
  if [ ] ; then echo true; else echo false; fi
always prints "false". So why did
  if [ $(id -u) ] ; then echo true; else echo false; fi
always print "true", regardless of `whoami`? The explanation is
that if I'd "taken care to suppress" the output:
  if [ $(id -u 2>&1 >/dev/null) ] ; then echo true; else echo false; fi
then it would print "false" instead. Right?

Here's my hypothesis: a shell command is like one of those classic C
functions that returns something and also potentially sets errno:
 - the shell command's return code is like C's errno
 - the C return value is like the shell command's output
Is that a helpful way of looking at it?

>  So this doesn't seem surprising to me at all. But I can't figure out what
> was your intention here, i.e. _why_ do you use the command expansion shell
> construct and what exactly do you expect to obtain from it?

Tackling my problematic command
  if [ $(curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1) ]; then
from the inside out, I thought as follows. This is the command I want to run:
         curl https://git.savannah.nongnu.org:443
This throws away 27 lines of output that I don't want to see:
         curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1

Now adding "$()":
       $(curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1)
means I only want the return code (0 if successful); so far, so good?
No. I already had the return code, without "$()". Adding "$()" means:
throw away the return code, and capture the text output--which would
have been implicitly printed on the screen, except that I discarded it.
Right? Well, maybe not. Consider the following commands, which
 - test a resolvable URL vs. one spoiled by adding 'X' after "https://";
 - with vs. without "$()"

$if curl https://Xgit.savannah.nongnu.org:443 >/dev/null 2>&1; then echo true; 
else echo false; fi 
false
$if curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1; then echo true; 
else echo false; fi 
true

$if $(curl https://Xgit.savannah.nongnu.org:443 >/dev/null 2>&1); then echo 
true; else echo false; fi
false
$if $(curl https://git.savannah.nongnu.org:443 >/dev/null 2>&1); then echo 
true; else echo false; fi 
true

The effects seem to be the same with or without "$()", so what does the
the "$()" do in this case? And why does it seem to make no difference?


reply via email to

[Prev in Thread] Current Thread [Next in Thread]