Technically, the extension $'\0' will always be an empty string '' (aka empty string) for the shell (not in zsh). Or, inversely worded, $'\0' will never expand to ascii NUL (or a byte with a null value), (again, not in zsh). It should be noted that it is confusing that both names are very similar: NUL and null .
However, when we talk about read -d '' , there is an arrogant (rather confusing) twist.
What read see - this is the value '' (empty string) as a separator.
What read does is splitting the input from stdin into the character $'\0' (yes the actual 0x00 ).
Extended answer.
Question in the caption:
In a bash script, what would evaluate $ '\ 0' and why?
This means that we need to explain why $'\0' extends.
The fact that $'\0' expands is very simple: it expands to the zero line '' (in most shells, not in zsh).
But an example of use:
read -r -d $'\0'
This converts the question to: what separator character $ '\ 0' expands to?
This has a very confusing twist. To correctly answer this question, we need to carry out a complete circuit when and how NUL (byte with a zero value or "0x00") is used in shells.
Flow.
We need a NUL to work. It is possible to create NUL bytes from the shell:
$ echo -e 'ab\0cd' | od -An -vtx1 61 62 00 63 64 0a ### That works in bash. $ printf 'ab\0cd' | od -An -vtx1 61 62 00 63 64
Variable
A variable in the shell will not store NUL.
$ printf -va 'ab\0cd'; printf '%s' "$a" | od -An -vtx1 61 62
The example is for bash, since only bash printf has the -v . But in this example, it is clear that a string containing NUL will be cut to NUL. Simple variables will cut the string in zero byte. What is reasonable to expect if the string is a C string, which should end in NUL \0 . Once the NUL is found, the line should end.
Command substitution.
NUL will work differently when used in command substitution. This code should assign the value to the variable $a , and then print it:
$ a=$(printf 'ab\0cd'); printf '%s' "$a" | od -An -vtx1
And this happens, but with different results in different shells:
#
Of particular note, bash (version 4.4) warns of the fact:
/bin/b44sh : warning: command substitution: ignored null byte in input 61 62 63 64
In command substitution, a zero byte is silently ignored by the shell.
It is very important to understand that this does not happen in zsh.
Now that we have all the parts about NUL. We can see what is reading.
What to read on the NUL delimiter.
This brings us back to the read -d $'\0' command:
while read -r -d $'\0' line; do
$'\0' shoud was expanded to a byte of value 0x00 , but the shell cuts it and actually becomes. '' This means that both $'\0' and '' are accepted by reading as the same value.
Having said that, it might seem reasonable to write an equivalent construct:
while read -r -d '' line; do
And this is technically correct.
What limits '' in fact.
There are two sides to this point, one of which is the character after the -d option to read, and the other that is addressed here is: what character will read if you set the delimiter to -d $'\0' ?
The first side was discussed in detail above.
The second side is very confusing, because the read command will actually read until the next byte of the value 0x00 (which means $'\0' ).
To actually show that this is so:
#!/bin/bash # create a test file with some zero bytes. printf 'ab\0cd\0ef\ngh\n' > tfile while true ; do read -r -d '' line; a=$? echo "exit $a" if [[ $a == 1 ]]; then printf 'last %s\n' "$line" break else printf 'normal %s\n' "$line" fi done <tfile
upon execution, the output will be:
$ ./script.sh exit 0 normal ab exit 0 normal cd exit 1 last ef gh
The first two exit 0 successfully read until the next "zero byte", and both contain the correct values ab and cd . The next read is the last (since there are no more null bytes) and contains the value $ 'ef \ ngh' (yes, it also contains a new line).
All this shows (and proves) that read -d '' does read until the next βnull byteβ, which is also known by the name ascii NUL and should have been the result of the extension $'\0' .
In short: we can safely say that read -d '' is read until the next 0x00 (NUL).
Output:
We must indicate that a read -d $'\0' will expand to the 0x00 delimiter. Using $'\0' is the best way to convey this correct meaning to the reader. As a thing of code style: I write $ '\ 0' so that my intentions are clear.
One and only one character used as a delimiter: byte value 0x00 (even if it is truncated in bash)
Note : Either these commands will print the hexadecimal values ββof the stream.
$ printf 'ab\0cd' | od -An -vtx1 $ printf 'ab\0cd' | xxd -p $ printf 'ab\0cd' | hexdump -v -e '/1 "%02X "' 61 62 00 63 64