22

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.

  • 1
    I suggest that you 1. use a wider terminal and/or editor window (e.g. i use a 192 column by 51 line terminal on my 1440p monitor - great for tailing log files and editing source code in vim) and 2. learn to accept the fact that sometimes source code lines will be longer than 80 characters - it's inevitable. If I used a smaller font, I could have an even wider terminal but my current setup is a good compromise between width and legibility. – cas Mar 26 '16 at 23:50
19

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
| improve this answer | |
  • @BinaryZebra I know. I just corrected the "for any shell" since not all shells have read and not all those that do have -p. – terdon Mar 27 '16 at 14:46
  • @terdon We are both in agreement That's the reason for the thanks :-). Thanks again. – user79743 Mar 27 '16 at 14:52
1

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
| improve this answer | |
  • 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 :) – Mateusz Piotrowski Mar 26 '16 at 22:31
  • 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. – Mateusz Piotrowski Mar 27 '16 at 1:37
1

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
| improve this answer | |
  • 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 Mar 26 '16 at 22:19
  • 1
    @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. – terdon Mar 26 '16 at 22:45
  • 1
    @MateuszPiotrowski done, I added a working version of what you were originally trying. – terdon Mar 27 '16 at 12:39
0

What about just this:

#!/bin/bash
read -p "Hello
world
this is a
multi-line
prompt:" PROMPT
echo $PROMPT

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.