Trying to embed newline in a variable in Bash

Bash

Bash Problem Overview


I have

var="a b c"
for i in $var
do
   p=`echo -e $p'\n'$i`
done
echo $p

I want the last echo to print:

a
b
c

Notice that I want the variable p to contain newlines. How do I do that?

Bash Solutions


Solution 1 - Bash

Summary

  1. Inserting \n

     p="${var1}\n${var2}"
     echo -e "${p}"
    
  2. Inserting a new line in the source code

     p="${var1}
     ${var2}"
     echo "${p}"
    
  3. Using $'\n' (only Bash and Z shell)

     p="${var1}"$'\n'"${var2}"
     echo "${p}"
    

Details

  1. Inserting \n

     p="${var1}\n${var2}"
     echo -e "${p}"
    

    echo -e interprets the two characters "\n" as a new line.

     var="a b c"
     first_loop=true
     for i in $var
     do
        p="$p\n$i"            # Append
        unset first_loop
     done
     echo -e "$p"             # Use -e
    

    Avoid extra leading newline

     var="a b c"
     first_loop=1
     for i in $var
     do
        (( $first_loop )) &&  # "((...))" is bash specific
        p="$i"            ||  # First -> Set
        p="$p\n$i"            # After -> Append
        unset first_loop
     done
     echo -e "$p"             # Use -e
    

    Using a function

     embed_newline()
     {
        local p="$1"
        shift
        for i in "$@"
        do
           p="$p\n$i"         # Append
        done
        echo -e "$p"          # Use -e
     }
    
     var="a b c"
     p=$( embed_newline $var )  # Do not use double quotes "$var"
     echo "$p"
    
  2. Inserting a new line in the source code

     var="a b c"
     for i in $var
     do
        p="$p
     $i"       # New line directly in the source code
     done
     echo "$p" # Double quotes required
               # But -e not required
    

    Avoid extra leading newline

     var="a b c"
     first_loop=1
     for i in $var
     do
        (( $first_loop )) &&  # "((...))" is Bash specific
        p="$i"            ||  # First -> Set
        p="$p
     $i"                      # After -> Append
        unset first_loop
     done
     echo "$p"                # No need -e
    

    Using a function

     embed_newline()
     {
        local p="$1"
        shift
        for i in "$@"
        do
           p="$p
     $i"                      # Append
        done
        echo "$p"             # No need -e
     }
    
     var="a b c"
     p=$( embed_newline $var )  # Do not use double quotes "$var"
     echo "$p"
    
  3. Using $'\n' (less portable)

    [tag:bash] and [tag:zsh] interprets $'\n' as a new line.

     var="a b c"
     for i in $var
     do
        p="$p"$'\n'"$i"
     done
     echo "$p" # Double quotes required
               # But -e not required
    

    Avoid extra leading newline

     var="a b c"
     first_loop=1
     for i in $var
     do
        (( $first_loop )) &&  # "((...))" is bash specific
        p="$i"            ||  # First -> Set
        p="$p"$'\n'"$i"       # After -> Append
        unset first_loop
     done
     echo "$p"                # No need -e
    

    Using a function

     embed_newline()
     {
        local p="$1"
        shift
        for i in "$@"
        do
           p="$p"$'\n'"$i"    # Append
        done
        echo "$p"             # No need -e
     }
    
     var="a b c"
     p=$( embed_newline $var )  # Do not use double quotes "$var"
     echo "$p"
    

The output is the same for all

a
b
c

Special thanks to contributors of this answer: kevinf, Gordon Davisson, l0b0, Dolda2000 and tripleee.


Solution 2 - Bash

The trivial solution is to put those newlines where you want them.

var="a
b
c"

Yes, that's an assignment wrapped over multiple lines.

However, you will need to double-quote the value when interpolating it, otherwise the shell will split it on whitespace, effectively turning each newline into a single space (and also expand any wildcards).

echo "$p"

Generally, you should double-quote all variable interpolations unless you specifically desire the behavior described above.

Solution 3 - Bash

Try echo $'a\nb'.

If you want to store it in a variable and then use it with the newlines intact, you will have to quote your usage correctly:

var=$'a\nb\nc'
echo "$var"

Or, to fix your example program literally:

var="a b c"
for i in $var; do
    p="`echo -e "$p\\n$i"`"
done
echo "$p"

Solution 4 - Bash

There are three levels at which a newline could be inserted in a variable. Well ..., technically four, but the first two are just two ways to write the newline in code.

1.1. At creation.

The most basic is to create the variable with the newlines already. We write the variable value in code with the newlines already inserted.

$ var="a
> b
> c"
$ echo "$var"
a
b
c

Or, inside script code:

var="a
b
c"

Yes, that means writing Enter where needed in the code.

1.2. Create using shell quoting.

The sequence $' is a special shell expansion in Bash and Z shell.

var=$'a\nb\nc'

The line is parsed by the shell and expanded to « var="anewlinebnewlinec" », which is exactly what we want the variable var to be. That will not work on older shells.

2. Using shell expansions.

It is basically a command expansion with several commands:

  1. echo -e

     var="$( echo -e "a\nb\nc" )"
    
  2. The Bash and Z shell printf '%b'

     var="$( printf '%b' "a\nb\nc" )"
    
  3. The Bash printf -v

     printf -v var '%b' "a\nb\nc"
    
  4. Plain simple printf (works in most shells):

     var="$( printf 'a\nb\nc' )"
    
3. Using shell execution.

All the commands listed in the second option could be used to expand the value of a variable, if that var contains special characters.

So, all we need to do is get those values inside the variable and execute some command to show:

var="a\nb\nc"                 # var will contain the characters \n not a newline.

echo -e "$var"                # use echo.
printf "%b" "$var"            # use bash %b in printf.
printf "$var"                 # use plain printf.

Note that printf is somewhat unsafe if the variable value is controlled by an attacker.

Solution 5 - Bash

There isn’t any need to use a for loop.

You can benefit from Bash parameter expansion functions:

var="a b c";
var=${var// /\\n};
echo -e $var
a
b
c

or just use tr:

var="a b c"
echo $var | tr " " "\n"
a
b
c

Solution 6 - Bash

sed solution:

echo "a b c" | sed 's/ \+/\n/g'

Result:

a
b
c

Solution 7 - Bash

var="a b c"
for i in $var
do
   p=`echo -e "$p"'\n'$i`
done
echo "$p"

The solution was simply to protect the inserted newline with a "" during current iteration when variable substitution happens.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnkur AgarwalView Question on Stackoverflow
Solution 1 - BashoHoView Answer on Stackoverflow
Solution 2 - BashtripleeeView Answer on Stackoverflow
Solution 3 - BashDolda2000View Answer on Stackoverflow
Solution 4 - Bashuser2350426View Answer on Stackoverflow
Solution 5 - Bashyoshi kakbudtoView Answer on Stackoverflow
Solution 6 - Bash0xAXView Answer on Stackoverflow
Solution 7 - BashAnkur AgarwalView Answer on Stackoverflow