shell Read Command – Why Exit 1 on EOF Encounter

readshell

The bash man page says the following about the read builtin:

The exit status is zero, unless end-of-file is encountered

This recently bit me because I had the -e option set and was using the following code:

read -rd '' json <<EOF
{
    "foo":"bar"
}
EOF

I just don't understand why it would be desirable to exit non successfully in this scenario. In what situation would this be useful?

Best Answer

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".