How does the -d option to bash read work?

6,430

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.

Share:
6,430

Related videos on Youtube

the_velour_fog
Author by

the_velour_fog

Updated on September 18, 2022

Comments

  • the_velour_fog
    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
    the_velour_fog over 8 years
    I 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
    mikeserv over 8 years
    @the_velour_fog - Then consider the paste at least. Or maybe some stuff with set -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
    the_velour_fog over 8 years
    yes 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
    chepner over 8 years
    It'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), so read 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 expecting read to succeed, such as if you are using set -e.
  • mikeserv
    mikeserv over 8 years
    @chepner - in most cases set -e is only used in poorly written shell scripts anyway.
  • user2059857
    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
    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.