What does the bash read -d '' do? What does the bash read -d '' do? bash bash

What does the bash read -d '' do?


In bash read builtin empty string delimiter -d '' behaves same as using delimiter as a NUL byte or $'\0' (as defined by ANSI C-quoted string) or in hex representation 0x0.

-d '' specifies that each input line should be delimited by a NUL byte. It means that input string is read up to the immediate next NUL character in each invocation of read.

Usually it is used with IFS= as:

IFS= read -r -d ''

for trimming leading and trailing whitespaces in input.

A common example of processing NUL delimited input is:

while IFS= read -r -d '' file; do    echo "$file"done < <(find . -type f -print0)
  • find command is printing files in current directory with NUL as the delimiter between each entry.
  • read -d '' sets \0 as delimiter for reading one entry at a time from output of find command.

Related: Why ‘read’ doesn’t accept \0 as a delimiter in this example?


read -d changes the character that stops the read from the default newline to the first character of the following argument.

The important thing to understand is that bash uses C strings, which are terminated by literal NULs. Thus, when the following argument is '', the first (and only) character is the NUL terminating it; thus, when the shell dereferences the char* to get the first character it points to, it gets a NUL.


Now, when you redirect a heredoc with <<EOF, that document won't actually have any NULs in it -- so how does your code work?

The answer is that your code expects the read operation to fail. Even when it fails, read still populates its destination variable; so if you don't have a terminating delimiter, read has a nonzero exit status... but it still puts all the data you wanted to collect in the variable anyhow!

For a version that doesn't trigger set -e errors, consider checking whether the destination variable is empty after the read is complete:

{ IFS= read -r -d '' string || [[ $string ]]; } <<'EOF'...string goes here...EOF

What are the changes we made?

  • IFS= prevents leading or trailing whitespace (or other characters, should IFS have been redefined) from being stripped.
  • read -r prevents content with backslash literals from being mangled.
  • || [[ $string ]] means that if read reports a failure, we then check whether the string was populated, and still consider the overall command a success should the variable be non-empty.