2

I have seen code like this in a /bin/sh script:


repo_files=$(git ls-files) &&  

There is no line continuation. What is the purpose of && at the end of a line like this? Can the 'logical and' && be placed at the end of a line for some logical mechanism?

3
  • 2
    What do you mean there's no line continuation? There must be something on a subsequent line or you get an error Commented Sep 17 at 12:41
  • 1
    The continuation aspect is addressed in this answer. If that doesn’t answer your question, feel free to comment and I’ll re-open this. Commented Sep 17 at 12:53
  • By 'no continuation' I mean there is no backslash at the end of that line that would make a boolean and operation having a second term. The line ends with `&&`` and the next line is empty. Commented Sep 17 at 13:05

1 Answer 1

7

From a syntax parsing point of view, &&, like ;, &, |, ||, separates commands and like in all of them, the following command doesn't have to be on the same line, you can have any number of blank lines (or lines containing only comments) in the interval:

if
   cmd1 &&

     # also checking this 2-command pipeline:

     cmd2 | # piped
            # to the command 2 lines below

       cmd3
then
   echo yes &
   echo not no at the same time
   wait
fi

For &&, || and | it's good practice to indent-out the following line to remind that its not independent from the previous one.

In all shells, ; and & don't have to be followed by another command. | does.

For && and ||, that depends on the shell.

Most shells require a following command (would error out if followed by the end of the script or of a compound command), zsh does not (and often allows commands to be omitted in positions where other shells don't, such as in { } or if cmd; then else echo else; fi (between then and else) or while echo forever; do done (between do and done)).

Even in zsh though, having && and || not followed by another command is not useful.

$ bash -c '(true &&)'
bash: -c: line 1: syntax error near unexpected token `)'
bash: -c: line 1: `(true &&)'
$ bash -c 'if true && then echo x; fi'
bash: -c: line 1: syntax error near unexpected token `then'
bash: -c: line 1: `if true && then echo x; fi'
$ zsh -c '(true &&)'
$ zsh -c 'if true && then echo x; fi'
x

There are not that many places that require a line-continuation (a \<newline> which is removed unless inside single quotes of here-document with quoted delimiter).

You can usually use a newline in place of a space except in cases where that would change the meaning.

Obviously, you can't replace:

echo foo \
  bar

With:

echo foo
  bar

As the former runs echo foo bar and the latter echo foo and bar.

But in Korn-like shells, you can do:

if
  a=$(
    echo "`
      uname
    `"
  ) &&
  ((
    2
    >
    1
  ))
then
  a=(
    x
    "$((
      1
      +
      1
    ))"
  )
  for i
  in a b
  do
    echo "$i"
  done
  case a
  in
    (a)
    echo a
  esac
fi

For instance.

There are a few instances, where newlines are not allowed in place of space, and it's not always clear why.

For instance, shells other than zsh complain about the newlines marked as ⚠️ below for no good reason:

[[⚠️
  alpha⚠️
    <⚠️
  zulu⚠️
]]

In:

for⚠️
  i
in⚠️
  a⚠️
  b
do
  ...
done

The second and following ⚠️ can be explained by the fact that one can do:

for word
in for in do done
do echo "$word is part of for loop constructs"
done

And to allow that unquoted do in the list of words to loop on, that list has to be separated from the do keyword with a newline or ;.

In zsh,

for
  i
in
  a b

Would be taken as for i in <empty-list>; a b, short for for i in <empty-list>; do a b; done.

There, to break down long lists of loop iterations without having to resort to line continuations, you can do:

for var (
  val1
  val2
  ...
) something with $var

(here short form, but you can also use do...done if you prefer).

I can't think of any reason why one couldn't do:

cmd >⚠️
  file

(other than it would look silly) but all shells I tried report a syntax error.

Also note that you can't do

echo foo
  && echo bar

The shell works one line at a time and tries to interpret the code as soon as it can after it's read it and it's syntactically valid.

After reading:

echo foo &&

The shell can't execute that yet, it needs the rest of the code that would make it syntactically valid. If interactive, it issues a $PS2 prompt to ask for more.

After reading:

echo foo

it runs echo foo, and forgets about it, ready to read, parse and runs whatever you feed it (remember shells were primarily designed to be run interactively).

Then, if you feed && echo bar, it won't know what to do with it, and errors out.

That's in contrast with the and/or keywords of the fish shell. There, you can do:

echo foo
and echo bar

In fish, and is still syntax in that for instance, you can do:

cmd1
and begin
      cmd2
      cmd3
    end

Which you couldn't if and was a regular builtin.

But the and is not syntactically connected to what's before.

Note you can't do:

cmd1
and
cmd2

Though.

1
  • I never realized you could chain commands with && like this. I previously assumed that the line had to be continued (with a backslash) . In the script I saw the command was not part of a n if statement, but it can still be used as a logical short circuit mechanism to stop on the first error. TIL! Commented Sep 17 at 13:15

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.