It appears the :
s in your script are being used in lieu of true
. If grep
doesn't find a match in the file, it will return a nonzero exit code; as jw013 mentions in a comment, if errexit
is set, probably by -e
on the shebang line, the script would exit if any of the grep
s fail to find a match. Clearly, that's not what the author wanted, so (s)he added || :
to make the exit status of that particular compound command always zero, like the more common (in my experience) || true
/|| /bin/true
.
It's because the part where you use the vars is a new set of commands. Use this instead:
head somefile | { read A B C D E FOO; echo $A $B $C $D $E $FOO; }
Note that, in this syntax, there must be a space after the {
and a ;
(semicolon) before the }
.
Also -n1
is not necessary; read
only reads the first line.
For better understanding, this may help you; it does the same as above:
read A B C D E FOO < <(head somefile); echo $A $B $C $D $E $FOO
Edit:
It's often said that the next two statements do the same:
head somefile | read A B C D E FOO
read A B C D E FOO < <(head somefile)
Well, not exactly. The first one is a pipe from head
to bash
's read
builtin. One process's stdout to another process's stdin.
The second statement is redirection and process substitution. It is handled by bash
itself. It creates a FIFO (named pipe, <(...)
) that head
's output is connected to, and redirects (<
) it to the read
process.
So far these seem equivalent. But when working with variables it can matter. In the first one the variables are not set after executing. In the second one they are available in the current environment.
Every shell has another behavior in this situation. See that link for which they are. In bash
you can work around that behavior with command grouping {}
, process substitution (< <()
) or Here strings (<<<
).
Best Answer
The syntax is:
which runs the second list of commands in a loop as long as the first list of commands (so the last run in that list) is successful.
In that first list of commands, you can use the
[
command to do various kinds of tests, or you can use the:
null command that does nothing and returns success, or any other command.Runs
cmd
over and over forever as:
always returns success. That's the forever loop. You could use thetrue
command instead to make it more legible:People used to prefer
:
as:
was always builtin whiletrue
was not (a long time ago; most shells havetrue
builtin nowadays)¹.Other variants you might see:
Above, we're calling the
[
command to test whether the "1" string is non-empty (so always true as well)Using the Korn/bash/zsh
((...))
syntax to mimic thewhile(1) { ...; }
of C.Or more convoluted ones like
until false; do cmd; done
,until ! true
...Those are sometimes aliased like:
So you can do something like:
Few people realise that the condition is a list of commands. For instance, you see people writing:
When they could have written:
It does make sense for it to be a list as you often want to do things like
while cmd1 && cmd2; do...; done
which are command lists as well.In any case, note that
[
is a command like any other (though it's built-in in modern Bourne-like shells), it doesn't have to be used solely in theif
/while
/until
condition lists, and those condition lists don't have to use that command more than any other command.¹
:
is also shorter and accepts arguments (which it ignores). While the behaviour oftrue
orfalse
is unspecified if you pass it any argument. So one may do for instance:But, the behaviour of:
is unspecified (though it would work in most shell/
false
implementations).