How to split strings over multiple lines in Bash?

Solution 1:

This is what you may want

$       echo "continuation"\
>       "lines"
continuation lines

If this creates two arguments to echo and you only want one, then let's look at string concatenation. In bash, placing two strings next to each other concatenate:

$ echo "continuation""lines"
continuationlines

So a continuation line without an indent is one way to break up a string:

$ echo "continuation"\
> "lines"
continuationlines

But when an indent is used:

$       echo "continuation"\
>       "lines"
continuation lines

You get two arguments because this is no longer a concatenation.

If you would like a single string which crosses lines, while indenting but not getting all those spaces, one approach you can try is to ditch the continuation line and use variables:

$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines

This will allow you to have cleanly indented code at the expense of additional variables. If you make the variables local it should not be too bad.

Solution 2:

Here documents with the <<-HERE terminator work well for indented multi-line text strings. It will remove any leading tabs from the here document. (Line terminators will still remain, though.)

cat <<-____HERE
    continuation
    lines
____HERE

See also http://ss64.com/bash/syntax-here.html

If you need to preserve some, but not all, leading whitespace, you might use something like

sed 's/^  //' <<____HERE
    This has four leading spaces.
    Two of them will be removed by sed.
____HERE

or maybe use tr to get rid of newlines:

tr -d '\012' <<-____
    continuation
     lines
____

(The second line has a tab and a space up front; the tab will be removed by the dash operator before the heredoc terminator, whereas the space will be preserved.)

For wrapping long complex strings over many lines, I like printf:

printf '%s' \
    "This will all be printed on a " \
    "single line (because the format string " \
    "doesn't specify any newline)"

It also works well in contexts where you want to embed nontrivial pieces of shell script in another language where the host language's syntax won't let you use a here document, such as in a Makefile or Dockerfile.

printf '%s\n' >./myscript \
    '#!/bin/sh` \
    "echo \"G'day, World\"" \
    'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript

Solution 3:

You can use bash arrays

$ str_array=("continuation"
             "lines")

then

$ echo "${str_array[*]}"
continuation lines

there is an extra space, because (after bash manual):

If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS variable

So set IFS='' to get rid of extra space

$ IFS=''
$ echo "${str_array[*]}"
continuationlines

Solution 4:

In certain scenarios utilizing Bash's concatenation ability might be appropriate.

Example:

temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines

From the PARAMETERS section of the Bash Man page:

name=[value]...

...In the context where an assignment statement is assigning a value to a shell variable or array index, the += operator can be used to append to or add to the variable's previous value. When += is applied to a variable for which the integer attribute has been set, value is evaluated as an arithmetic expression and added to the variable's current value, which is also evaluated. When += is applied to an array variable using compound assignment (see Arrays below), the variable's value is not unset (as it is when using =), and new values are appended to the array beginning at one greater than the array's maximum index (for indexed arrays) or added as additional key-value pairs in an associative array. When applied to a string-valued variable, value is expanded and appended to the variable's value.