ifne
doesn't set an exit code based on whether the input is empty or not, so &&
and ||
aren't going to work as hoped. An alternate approach to Babyy's answer is to use pee
from the same package:
printf "asdf\n" | pee 'ifne cat -' 'ifne echo "stream not empty"'
This works like tee
, but duplicates the input stream into a number of pipes, treating each argument as a command to run. (tpipe
is a similar command, but behaves slightly differently.)
A possible issue though is that each of the commands may be writing to stdout in parallel, depending on buffering and length of input/output there is a chance that output will be interleaved, or vary from run to run (effectively a race). This can probably be eliminated using sponge
(same package) instead of cat
, and/or other buffering/unbuffering solutions. It affects the example you gave, but may not affect your real use-case.
read a b
reads two words from one line (words delimited by $IFS
characters and word and line delimiters escaped with \
).
Your python
script outputs 2 lines.
Older versions of bash
had a bug in that cmd <<< $var
or cmd <<< $(cmd2)
was applying word splitting to the expansion of $var
and $(cmd2)
and joining the resulting elements back with spaces do make up the contents of the here-string (see for instance Why does cut fail with bash and not zsh?).
That was fixed in version 4.4 which explains why you don't get what you expect any longer.
To read the first two lines of the output of a command into the $a
and $b
variable in bash
, use:
{
IFS= read -r a
IFS= read -r b
} < <(cmd)
Or (not in interactive shells):
shopt -s lastpipe
cmd | {
IFS= read -r a
IFS= read -r b
}
Or without lastpipe
:
cmd | {
IFS= read -r a
IFS= read -r b
something with "$a" and "$b"
}
# $a and $b will be lost after the `{...}` command group returns
To join lines of the output of a command with spaces, use: cmd | paste -sd ' ' -
. Then you can do:
IFS=' ' read -r a b < <(cmd | paste -sd ' ' -)
If you like.
You can also read the lines into elements an array with:
readarray -t array < <(cmd)
And join the elements of the array with the first character of $IFS
(space by default) with "${array[*]}"
.
Best Answer
Yes, this is expected behaviour. When only one argument is passed to
test
, a length check is performed. Fromman bash
:That is, essentially it is the equivalent of
test foo
, but using-n
as the string.