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

Tags:

Shell

Read