How to break a long string into multiple lines in the prompt of read -p within the source code?

69,033

Solution 1

First of all, let's decouple the read from the text line by using a variable:

text="line-1 line-2"             ### Just an example.
read -p "$text" REPLY

In this way the problem becomes: How to assign two lines to a variable.

Of course, a first attempt to do that, is:

a="line-1 \
line-2"

Written as that, the var a actually gets the value line-1 line-2.

But you do not like the lack of indentation that this creates, well, then we may try to read the lines into the var from a here-doc (be aware that the indented lines inside the here-doc need a tab, not spaces, to work correctly):

    a="$(cat <<-_set_a_variable_
        line-1
        line-2
        _set_a_variable_
    )"
echo "test1 <$a>"

But that would fail as actually two lines are written to $a. A workaround to get only one line might be:

    a="$( echo $(cat <<-_set_a_variable_
        line 1
        line 2
        _set_a_variable_
        ) )"
echo "test2 <$a>"

That is close, but creates other additional issues.

Correct solution.

All the attempts above will just make this problem more complex that it needs to be.

A very basic and simple approach is:

a="line-1"
a="$a line-2"
read -p "$a" REPLY

The code for your specific example is (for any shell whose read supports -p):

#!/bin/dash
    a="goat can try change directory if cd fails to do so."
    a="$a Would you like to add this feature? [Y|n] "
# absolute freedom to indent as you see fit.
        read -p "$a" REPLY

For all the other shells, use:

#!/bin/dash
    a="goat can try change directory if cd fails to do so."
    a="$a Would you like to add this feature? [Y|n] "
# absolute freedom to indent as you see fit.
        printf '%s' "$a"; read REPLY

Solution 2

I find @BinaryZebra's approach using a variable to be cleaner, but you can also do it the way you were attempting. You just need to keep the line breaks inside the quotes:

read -p "goat can try change directory if cd fails to do so. \
Would you like to add this feature? [Y|n] " REPLY

Solution 3

The backslash at the end of the lines is allowing the continuation of the command over multiple lines, not actual line breaks in the output.

So your first approach, for example, becomes the command

read -p "goat can try change directory if cd fails to do so. " "Would you like to add this feature? [Y|n] " REPLY

I'm not sure why you want read to output multiple lines, but I would simply use read for the prompt line and echo the preceding line(s).

To make the code more readable over multiple lines, don't close/open your quotes between lines.

Try this:

read -p "goat can try change directory if cd fails to do so. \
Would you like to add this feature? [Y|n] " REPLY
Share:
69,033

Related videos on Youtube

Mateusz Piotrowski
Author by

Mateusz Piotrowski

Updated on September 18, 2022

Comments

  • Mateusz Piotrowski
    Mateusz Piotrowski almost 2 years

    I am writing an installation script that will be run as /bin/sh.

    There is a line prompting for a file:

    read -p "goat may try to change directory if cd fails to do so. Would you like to add this feature? [Y|n] " REPLY
    

    I would like to break this long line into many lines so that none of them exceed 80 characters. I'm talking about the lines within the source code of the script; not about the lines that are to be actually printed on the screen when the script is executed!

    What I've tried:

    • Frist approach:

      read -p "oat may try to change directory if cd fails to do so. " \
          "Would you like to add this feature? [Y|n] " REPLY
      

      This doesn't work since it doesn't print Would you like to add this feature? [Y|n].

    • Second approach:

      echo "oat may try to change directory if cd fails to do so. " \
          "Would you like to add this feature? [Y|n] "
      read REPLY
      

      Doesn't work as well. It prints a newline after the prompt. Adding -n option to echo doesn't help: it just prints:

      -n goat oat may try to change directory if cd fails to do so. Would you like to add this feature? [Y|n]
      # empty line here
      
    • My current workaround is

      printf '%s %s ' \
          "oat may try to change directory if cd fails to do so." \
          "Would you like to add this feature? [Y|n] "
      read REPLY
      

    and I wonder if there is a better way.

    Remember that I am looking for a /bin/sh compatible solution.

  • Mateusz Piotrowski
    Mateusz Piotrowski over 8 years
    Do you think that adding newlines after every line would increase the readability? Because I wasn't looking for the way to insert \n into my prompt. I just wanted to break the code into multiple lines so that every line is at most 80 characters long.
  • Mateusz Piotrowski
    Mateusz Piotrowski over 8 years
    I don't want it to print two lines! I just want the code to fit in 80 characters per line in the source code of the script! Thank you for the answer though :)
  • terdon
    terdon over 8 years
    @MateuszPiotrowski oh, that makes a lot more sense. Then my answer isn't very useful. Please edit your question and clarify that you want to split the code and not the output. I'm on mobile now but I'll see if I can come up with something tomorrow.
  • Mateusz Piotrowski
    Mateusz Piotrowski about 8 years
    I don't like the approach you suggested because there is no indentation. If my read is indented within a function then your approach seems to mess the readability.
  • terdon
    terdon about 8 years
    @MateuszPiotrowski done, I added a working version of what you were originally trying.
  • terdon
    terdon about 8 years
    @BinaryZebra I know. I just corrected the "for any shell" since not all shells have read and not all those that do have -p.
  • Admin
    Admin about 8 years
    @terdon We are both in agreement That's the reason for the thanks :-). Thanks again.
  • Mateusz Piotrowski
    Mateusz Piotrowski over 5 years
    How do you indent it?