For what purpose does "read" exit 1 when EOF is encountered?
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".
This is one of the reasons I don't use set -e
myself.
Now that you know that read will return 1 if it hits EOF without the given EOL delimeter, you can do one of:
# depending on the contents of the input, it's an error
# if no data was read:
IFS= read -rd '' json <<EOF || [[ -n $json ]]
...
EOF
# or, you don't care at all how much data was read
IFS= read -rd '' json <<EOF || :
...
EOF