What needs to be explained is that the command appeared to work, not its exit code
'\n' is two characters: a backslash \ and a letter n. What you thought you needed was
$'\n', which is a linefeed (but that wouldn't be right either, see below).
-d option does this:
-d delim continue until the first character of DELIM is read, rather
So without that option,
read would read up to a newline, split the line into words using the characters in
$IFS as separators, and put the words into the array. If you specified
-d $'\n', setting the line delimiter to a newline, it would do exactly the same thing. Setting
-d '\n' means that it will read up to the first backslash (but, once again, see below), which is the first character in
delim. Since there is no backslash in your file, the
read will terminate at the end of file, and:
The return code is zero, unless end-of-file is encountered, read times out,
or an invalid file descriptor is supplied as the argument to -u.
So that's why the exit code is 1.
From the fact that you believe that the command worked, we can conclude that there are no spaces in the file, so that
read, after reading the entire file in the futile hope of finding a backslash, will split it by whitespace (the default value of
$IFS), including newlines. So each line (or each word, if a line contains more than one word) gets stashed into the array.
The mysterious case of the purloined backslash
Now, how did I know the file didn't contain any backslashes? Because you didn't supply the
-r flag to
-r do not allow backslashes to escape any characters
So if you had any backslashes in the file, they would have been stripped, unless you had two of them in a row. And, of course, there is the evidence that
read had an exit code of 1, which demonstrates that it didn't find a backslash, so there weren't two of them in a row either.
Bash wouldn't be bash if there weren't gotchas hiding behind just about every command, and
read is no exception. Here are a couple:
Unless you specify
read will interpret backslash escape sequences. Unless that's actually what you want (which it occasionally is, but only occasionally), you should remember to specify
-r to avoid having characters disappear in the rare case that there are backslashes in the input.
The fact that
read returns an exit code of 1 does not mean that it failed. It may well have succeeded, except for finding the line terminator. So be careful with a loop like this:
while read -r LINE; do something with LINE; done
because it will fail to
do something with the last line in the rare case that the last line doesn't have a newline at the end.
read -r LINE preserves backslashes, but it doesn't preserve leading or trailing whitespace.