How does the -d option to bash read work?
Solution 1
I guess the question is why read -d ''
works though read -d''
doesn't.
The problem doesn't have anything to do with read
but is a quoting "problem". A ""
/ ''
which is part of a string (word) simply is not recognized at all. Let the shell show you what is sees / executes:
start cmd:> set -x
start cmd:> echo read -d " " foo
+ echo read -d ' ' foo
start cmd:> echo read -d" " foo
+ echo read '-d ' foo
start cmd:> echo read -d "" foo
+ echo read -d '' foo
start cmd:> echo read -d"" foo
+ echo read -d foo
Solution 2
Your heredoc thing is a lot more simply written like:
print_status(){ paste -sd\\n /dev/null - /dev/null;}
print_status <<\doc
doc body
doc
You dont have to assign all of that to a name. For that matter, more simply still it could be:
print_status(){ printf %s\\n '' "$@" '';}
print_status \
'line 2' \
'line 3' and lines 4,5,6
My point is it that I think it is a little over the top to write a bunch of text into your script file which you then instruct the shell to read out to a temporary file (which is generally how here-documents work) and to open that temporary file on some command's stdin if your targeted command is just meant to be the shell all over again reading it back into a variable! See? It's a little redundant, in my opinion.
Related videos on Youtube
the_velour_fog
Updated on September 18, 2022Comments
-
the_velour_fog over 1 year
I have a bash script where I'm trying to assign a heredoc string to a variable using read, and it only works if I use
read
with the-d ''
option, I.e.read -d '' <variable>
script block
#!/usr/bin/env bash function print_status() { echo echo "$1" echo } read -d '' str <<- EOF Setup nginx site-config NOTE: if an /etc/nginx/sites-available config already exists for this website, this routine will replace existing config with template from this script. EOF print_status "$str"
I found this answer on SO which is where I copied the command from, it works, but why? I know the first invocation of
read
stops when it encounters the first newline character, so if I use some character that doesn't appear in the string the whole heredoc gets read in, e.g.-
read -d '|' <variable>
-- this works -
read -d'' <variable>
-- this doesn't
I'm sure it's simple but what's going on with this
read -d ''
command option? -
-
the_velour_fog over 8 yearsI see what you mean, so by passing the
""
read will be looking for an empty string which is technically a non-existent character - so read will read in the whole string. But you still need to pass""
so that the-d
argument works - even though you are kind of "tricking" it, thanks -
mikeserv over 8 years@the_velour_fog - Then consider the
paste
at least. Or maybe some stuff withset -v
and comments. And anyway its fine as long as youre fully aware of what youre doing and its worth it to you then go ahead, and with my blessing. I only wanted to speak up because quite often people dont consider that stuff - i didnt used to, anyway. -
the_velour_fog over 8 yearsyes i see what you mean, it looks like you have a couple of patterns that definitely will make the code cleaner so I will give them a try!
-
chepner over 8 yearsIt's also worth nothing that
read -d ''
is a bit of a hack. You aren't specifying any character to look for as the end of a line (or possibly you are looking for the null character, ASCII 0, which due to implementation details cannot occur in a string), soread
always just reads up to the end of its input, at which point it exits with a non-zero exit status because it never found the requested end-of-line character. This can be an issue if you are expectingread
to succeed, such as if you are usingset -e
. -
mikeserv over 8 years@chepner - in most cases
set -e
is only used in poorly written shell scripts anyway. -
user2059857 over 5 years@mikeserv If switching on
-e
breaks a shell script. Than it is a poor shell script. I always use-e
. -
Eugene over 2 years@chepner I was looking for such a human readable explanation for far too much, for someone that only sometimes writes scripts, this was a fabulous comment.