0

I have this bash statement:

if ls > /dev/null 2>&1 -a ls > /dev/null 2>&1; then
    echo "true"; 
else 
    echo "false"; 
fi

Which gives me "false". But I know ls will always return 0 (i.e. true). I had thought that -a was an AND statement.

When I change this to:

if ls > /dev/null 2>&1 && ls > /dev/null 2>&1; then
    echo "true"; 
else 
    echo "false"; 
fi

It works. What's going on differently here? Is -a not an AND operator?

Connor
  • 4,216
  • 2
  • 29
  • 40
  • 2
    BTW, it's more efficient to use `grep -q "state UP"` and not bother with the `>/dev/null`. When `grep` knows you don't need the output, it (1) doesn't bother writing it, even to `/dev/null` where it's throw away; and (2) can exit immediately as soon as a match is seen, not needing to read the rest of the input stream. – Charles Duffy Jun 21 '18 at 15:11
  • @CharlesDuffy Thank you for your note on the `grep -q "state UP"` I'll use that in the future. For anyone who finds this in the future, this question used to have this command: `ip link show eth1 | grep "state UP" > /dev/null 2>&1` which I edited out for simplicity sake. – Connor Jun 23 '18 at 20:43

1 Answers1

2

&& is the correct way to perform a short-circuiting logical AND in bash.

-a is a test operand (test is the command also named [). It does not mean AND in any other context (built into bash; it is also a predicate in find, for example). Moreover, the POSIX specification for test has it marked "obsolescent"; search for OB within the linked page.

The above is also to say that [ -n "$foo" ] && [ -n "$bar" ], or [[ $foo && $bar ]], is better practice than [ -n "$foo" -a -n "$bar" ].

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • shell syntax, in general, is extremely context-dependent. That is, the meaning of various symbols depends a great deal on where it occurs. `&&` means "logical and" when it's between commands (as in `[ -n "$foo" ] && [ -n "$bar" ]`), or inside `[[ ]]` or `(( ))`, but *not* inside `[ ]`. `-a` means "logical and" *only* when it occurs inside `[ ]` (and then only in some positions). This is just one of many examples of this context-dependence. – Gordon Davisson Jun 21 '18 at 16:21
  • I'm hesitant to call `-a` shell syntax at all -- it's part of the `test` specification, not part of the [shell command language](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html), whereas `&&` *is* a part of that language. – Charles Duffy Jun 21 '18 at 16:23
  • I don't disagree, but I consider that distinction part of the context-dependence I was talking about. – Gordon Davisson Jun 22 '18 at 01:17
  • It's this sort of thing that makes me hate bash: "or inside `[[ ]]` or `(( ))`, but not inside `[ ]`". Is there an approachable way to learn this stuff that will make it seem motivated and cogent rather than it feeling like the odious, poorly considered, duct-taped, inaccessible mess that it seems to me right now? – Connor Jun 23 '18 at 20:46
  • @Connor, `[ ]`, aka the `test` command, is from the 1970s -- it long predates `[[ ]]` and `(( ))` (which are not an external command but parser-recognized syntax), and it *isn't part of bash at all* (except insofar as bash has a built-in implementation of what otherwise would be an external command for better performance). It'd be helpful to start by just learning the shell command language, and ignoring everything else -- when you don't think (wrongly) that `[` is part of bash, you can't mistake `[`'s syntax with the shell's. – Charles Duffy Jun 24 '18 at 03:15
  • 1
    @Connor, ...so, what you're putting down to someone making a really horrid design decision was rather someone trying to fix someone else's decades-prior design *oversight* in a manner that avoids backwards incompatibilities. Bash is full of that, yes, but given context and history the rationale becomes much less mysterious. – Charles Duffy Jun 24 '18 at 03:17
  • @CharlesDuffy I can accept that as the case, it doesn't make it any more enjoyable. Any resources for learning shell command language in depth that you recommend? I can also go hunting myself, just thought I'd ask – Connor Jun 24 '18 at 03:29
  • 1
    The POSIX spec (linked above) is the canonical resource; the [bash-hackers' wiki](http://wiki.bash-hackers.org/) is a little less canonical, but a fair bit more accessible while still being accurate and keeping a focus on best practices. For a slower, tutorial-style document I suggest the [BashGuide](http://mywiki.wooledge.org/BashGuide), or the [BashFAQ](http://mywiki.wooledge.org/BashFAQ) and [BashPitfalls](http://mywiki.wooledge.org/BashPitfalls) documents for folks trying to quickly identify places where there's room to fill in their existing understanding. – Charles Duffy Jun 24 '18 at 03:42