37

Working with printf in a bash script, adding no spaces after "\n" does not create a newline, whereas adding a space creates a newline, e. g.:

  1. No space after "\n"

    NewLine=`printf "\n"`
    echo -e "Firstline${NewLine}Lastline"
    

    Result:

    FirstlineLastline
    
  2. Space after "\n "

    NewLine=`printf "\n "`
    echo -e "Firstline${NewLine}Lastline"
    

    Result:

    Firstline
     Lastline
    

Question: Why doesn't 1. create the following result:

Firstline 
Lastline

I know that this specific issue could have been worked around using other techniques, but I want to focus on why 1. does not work.

Edited: When using echo instead of printf, I get the expected result, but why does printf work differently?

    NewLine=`echo "\n"`
    echo -e "Firstline${NewLine}Lastline"

Result:

    Firstline
    Lastline
WolfHumble
  • 373
  • 1
  • 3
  • 6

9 Answers9

36

The backtick operator removes trailing new lines. See 3.4.5. Command substitution at http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html

Note on edited question

Compare:

[alvaro@localhost ~]$ printf "\n"

[alvaro@localhost ~]$ echo "\n"
\n
[alvaro@localhost ~]$ echo -e "\n"


[alvaro@localhost ~]$

The echo command doesn't treat \n as a newline unless you tell him to do so:

NAME
       echo - display a line of text
[...]
       -e     enable interpretation of backslash escapes

POSIX 7 specifies this behaviour here:

[...] with the standard output of the command, removing sequences of one or more characters at the end of the substitution

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • The thing is that this does not seem to be the case for the example in the edited part of the post, i.e the part: NewLine=`echo "\n"` – WolfHumble Apr 20 '10 at 22:31
  • So I guess the **conclusion** is that: **1)** Printf works differently than echo in this case, in that echo requires "-e" for creating the actual newline **2)** All trailing newlines gets deleted, both in printf and in echo -e, as described in: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html The post by mr. Dennis Williamson below was also useful to point out these issues. Thx! – WolfHumble Apr 22 '10 at 11:32
  • 2
    Is there a POSIX 7 workaround to avoid that behavior (I want to keep newlines), except writing to temp files or pipes? – Ciro Santilli OurBigBook.com Jul 28 '13 at 16:00
8

Maybe people will come here with the same problem I had: echoing \n inside a code wrapped in backsticks. A little tip:

printf "astring\n"
# and 
printf "%s\n" "astring" 
# both have the same effect.
# So... I prefer the less typing one

The short answer is:

# Escape \n correctly !

# Using just: printf "$myvar\n" causes this effect inside the backsticks:
printf "banana
"

# So... you must try \\n  that will give you the desired 
printf "banana\n"

# Or even \\\\n if this string is being send to another place 
# before echoing,

buffer="${buffer}\\\\n printf \"$othervar\\\\n\""

One common problem is that if you do inside the code:

echo 'Tomato is nice'

when surrounded with backsticks will produce the error

command Tomato not found.

The workaround is to add another echo -e or printf

printed=0

function mecho(){
  #First time you need an "echo" in order bash relaxes.
  if [[ $printed == 0 ]]; then
    printf "echo -e $1\\\\n"
    printed=1
  else
    echo -e "\r\n\r$1\\\\n"
  fi
}

Now you can debug your code doing in prompt just:

(prompt)$  `mySuperFunction "arg1" "etc"`

The output will be nicely

 mydebug: a value
 otherdebug: whathever appended using myecho
 a third string

and debuging internally with

mecho "a string to be hacktyped"
Sergio Abreu
  • 2,686
  • 25
  • 20
6
$ printf -v NewLine "\n"
$ echo -e "Firstline${NewLine}Lastline"

Firstline
Lastline

$ echo "Firstline${NewLine}Lastline"
Firstline
Lastline
Robert S
  • 61
  • 1
  • 1
4

It looks like BASH is removing trailing newlines. e.g.

NewLine=`printf " \n\n\n"`
echo -e "Firstline${NewLine}Lastline"
Firstline Lastline

NewLine=`printf " \n\n\n "`
echo -e "Firstline${NewLine}Lastline"
Firstline


 Lastline
an0nym0usc0ward
  • 1,207
  • 8
  • 8
4

Your edited echo version is putting a literal backslash-n into the variable $NewLine which then gets interpreted by your echo -e. If you did this instead:

NewLine=$(echo -e "\n")
echo -e "Firstline${NewLine}Lastline"

your result would be the same as in case #1. To make that one work that way, you'd have to escape the backslash and put the whole thing in single quotes:

NewLine=$(printf '\\n')
echo -e "Firstline${NewLine}Lastline"

or double escape it:

NewLine=$(printf "\\\n")

Of course, you could just use printf directly or you can set your NewLine value like this:

printf "Firstline\nLastline\n"

or

NewLine=$'\n'
echo "Firstline${NewLine}Lastline"    # no need for -e
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • this is confusing and -- if one where to nitpick -- also wrong. for example: in the second code block you say you escape the newline but you really only escape the backslash (the "escape"). –  Apr 20 '10 at 17:43
  • Sorry for the confusion. I'll try to clarify it. – Dennis Williamson Apr 20 '10 at 19:28
  • Thx. for this answer as well. Was not able to upvote it because "it was to old to be changed", according to the system. – WolfHumble Apr 22 '10 at 11:41
4

For people coming here wondering how to use newlines in arguments to printf, use %b instead of %s:

$> printf "a%sa" "\n"
a\na
$> printf "a%ba" "\n"
a
a

From the manual:

%b expand backslash escape sequences in the corresponding argument

rethab
  • 7,170
  • 29
  • 46
1

We do not need "echo" or "printf" for creating the NewLine variable:

NewLine="
"
printf "%q\n" "${NewLine}"
echo "Firstline${NewLine}Lastline"
yabt
  • 11
  • 1
0

Bash delete all trailing newlines in commands substitution.

To save trailing newlines, assign printf output to the variable with printf -v VAR

instead of

NewLine=`printf "\n"`
echo -e "Firstline${NewLine}Lastline"
#FirstlineLastline

use

printf -v NewLine '\n'
echo -e "Firstline${NewLine}Lastline"
#Firstline
#Lastline

Explanation

According to bash man

3.5.4 Command Substitution

$(command)

or

`command`

Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting.

So, after adding any trailing newlines, bash will delete them.

var=$(printf '%s\n%s\n\n\n' 'foo' 'bar')
echo "$var"

output:

foo
bar

According to help printf

printf [-v var] format [arguments]

If the -v option is supplied, the output is placed into the value of the shell variable VAR rather than being sent to the standard output.

In this case, for safe copying of formatted text to the variable, use the [-v var] option:

printf -v var '%s\n%s\n\n\n' 'foo' 'bar'
echo "$var"

output:

foo
bar




Lad
  • 81
  • 1
  • 3
-3

Works ok if you add "\r"

$ nl=`printf "\n\r"` && echo "1${nl}2"
1
2
Oleg Razgulyaev
  • 5,757
  • 4
  • 28
  • 28