How to split strings over multiple lines in Bash?

前端 未结 11 1098
[愿得一人]
[愿得一人] 2020-11-29 16:35

How can i split my long string constant over multiple lines?

I realize that you can do this:

echo "continuation \\
lines"
>continuation li         


        
相关标签:
11条回答
  • 2020-11-29 17:18

    You could simply separate it with newlines (without using backslash) as required within the indentation as follows and just strip of new lines.

    Example:

    echo "continuation
    of 
    lines" | tr '\n' ' '
    

    Or if it is a variable definition newlines gets automatically converted to spaces. So, strip of extra spaces only if applicable.

    x="continuation
    of multiple
    lines"
    y="red|blue|
    green|yellow"
    
    echo $x # This will do as the converted space actually is meaningful
    echo $y | tr -d ' ' # Stripping of space may be preferable in this case
    
    0 讨论(0)
  • 2020-11-29 17:25

    Depending on what sort of risks you will accept and how well you know and trust the data, you can use simplistic variable interpolation.

    $: x="
        this
        is
           variably indented
        stuff
       "
    $: echo "$x" # preserves the newlines and spacing
    
        this
        is
           variably indented
        stuff
    
    $: echo $x # no quotes, stacks it "neatly" with minimal spacing
    this is variably indented stuff
    
    0 讨论(0)
  • 2020-11-29 17:29

    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
    
    0 讨论(0)
  • 2020-11-29 17:29

    I came across a situation in which I had to send a long message as part of a command argument and had to adhere to the line length limitation. The commands looks something like this:

    somecommand --message="I am a long message" args
    

    The way I solved this is to move the message out as a here document (like @tripleee suggested). But a here document becomes a stdin, so it needs to be read back in, I went with the below approach:

    message=$(
        tr "\n" " " <<- END
            This is a
            long message
    END
    )
    somecommand --message="$message" args
    

    This has the advantage that $message can be used exactly as the string constant with no extra whitespace or line breaks.

    Note that the actual message lines above are prefixed with a tab character each, which is stripped by here document itself (because of the use of <<-). There are still line breaks at the end, which are then replaced by dd with spaces.

    Note also that if you don't remove newlines, they will appear as is when "$message" is expanded. In some cases, you may be able to workaround by removing the double-quotes around $message, but the message will no longer be a single argument.

    0 讨论(0)
  • 2020-11-29 17:32

    However, if you have indented code, it doesn't work out so well:

        echo "continuation \
        lines"
    >continuation     lines
    

    Try with single quotes and concatenating the strings:

        echo 'continuation' \
        'lines'
    >continuation lines
    

    Note: the concatenation includes a whitespace.

    0 讨论(0)
  • 2020-11-29 17:34

    This probably doesn't really answer your question but you might find it useful anyway.

    The first command creates the script that's displayed by the second command.

    The third command makes that script executable.

    The fourth command provides a usage example.

    john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n    """Dedent all but the first line in the passed `text`."""\n    try:\n        first, rest = text.split("\\n", 1)\n        return "\\n".join([first, textwrap.dedent(rest)])\n    except ValueError:\n        return text  # single-line string\n\nprint bash_dedent(sys.argv[1])'  > bash_dedent
    john@malkovich:~/tmp/so$ cat bash_dedent 
    #!/usr/bin/env python
    import textwrap, sys
    
    def bash_dedent(text):
        """Dedent all but the first line in the passed `text`."""
        try:
            first, rest = text.split("\n", 1)
            return "\n".join([first, textwrap.dedent(rest)])
        except ValueError:
            return text  # single-line string
    
    print bash_dedent(sys.argv[1])
    john@malkovich:~/tmp/so$ chmod a+x bash_dedent
    john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
    >     second line
    >     third line")"
    first line
    second line
    third line
    

    Note that if you really want to use this script, it makes more sense to move the executable script into ~/bin so that it will be in your path.

    Check the python reference for details on how textwrap.dedent works.

    If the usage of $'...' or "$(...)" is confusing to you, ask another question (one per construct) if there's not already one up. It might be nice to provide a link to the question you find/ask so that other people will have a linked reference.

    0 讨论(0)
提交回复
热议问题