read
reads a record (line by default, but ksh93/bash/zsh allow other delimiters with -d
, even NUL with zsh/bash) and returns success as long as a full record has been read.
read
returns non-zero when it finds EOF while the record delimiter has still not been encountered.
That allows you do do things like
while IFS= read -r line; do
...
done < text-file
Or with zsh/bash
while IFS= read -rd '' nul_delimited_record; do
...
done < null-delimited-list
And that loop to exit after the last record has been read.
You can still check if there was more data after the last full record with [ -n "$nul_delimited_record" ]
.
In your case, read
's input doesn't contain any record as it doesn't contain any NUL character. In bash
, it's not possible to embed a NUL inside a here document. So read
fails because it hasn't managed to read a full record. It stills stores what it has read until EOF (after IFS processing) in the json
variable.
In any case, using read
without setting $IFS
rarely makes sense.
For more details, see Understanding "IFS= read -r line".
while read -r line || [[ -n $line ]]
mean?grep
when it doesn't find a match,cmp
anddiff
when the files don't match, even(( someexpression ))
when the expression evaluates to 0 ("false" in arithmetic context).read
behavior does make sense, because it failed to read a complete record (including terminator) from its input.set -e
routinely.