2

Sometimes simplest things take your time in shell scripting like crazy.

Content='me \n you \n him \n'
echo $Content > Names.txt

When I open the Names.txt it has two empty lines at the end.

I want it to only have one empty line. The Content variable is calculated in a loop and in each iteration it adds a new line to it. Thus I can't change Content.

I can't use echo -n because it removes all new lines.

I can't remove the \n from my loop, because in that case all lines are concatenated to each other.

I tried Content=$(echo $Content | awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}') to use awk to remove the trailing newline, but it does not work. I took it from an answer on this site.

I tried to use printf %s $Content > File.txt instead of echo -e, still no success.

How can I either remove the trailing newline from a given string variable or write it as is to the file and tell Linux not to append yet another line to it?

3 Answers3

11

it's not Linux adding that second newline, it's your bash when you call echo!

So, the answer can be found in the documentation to your shell's builtin funcitons, man builtins:

  echo [-neE] [arg ...]
          Output the args, separated by spaces, followed by a newline.
          The return status is 0 unless a write error occurs.  If -n
          is specified, the trailing newline is suppressed.

So, echo -n does the trick. In fact, you will need to use echo -ne, because without -e, your file ends up containing the literal string

me \n you \n him \n

(with the "backslash n" in there!!)

I can't use echo -n because it removes all new lines.

No, it doesn't do that.


Edit: The following dialogue of commands and their output, when running in bash confirm the statements above:

$ Content='me \n you \n him \n'
$ echo $Content > Names.txt
$ cat Names.txt 
me \n you \n him \n
$ echo -e "$Content" > Names.txt 
$ cat Names.txt 
me 
 you 
 him

$ echo -en "$Content" > Names.txt $ cat Names.txt me you him $

sudodus
  • 6,421
  • 1
    "No, it doesn't do that." in fact it does, because in his own shell the '\n' are expanded as soon as parsed in $Contents opposite to yours or mine where ' \n' are expanded only when echo -e – Thibault LE PAUL Jul 01 '22 at 08:41
  • how so, the shell is bash, according to tags, and '\n' in bash remains unexpanded (or so I thought!) – Marcus Müller Jul 01 '22 at 08:53
  • I agree, either the exposed code is not as really executed, or bash does something unexpected, or there is some settings, but all what is reported denote actual newlines in the variable value, not \n. The fact echo -e were unneeded, the fact newlines were removed ... – Thibault LE PAUL Jul 01 '22 at 09:03
6

Using printf with %b format:

%b ARGUMENT as a string with '' escapes interpreted, except that octal escapes are of the form \0 or \0NNN

$ Content='me \n you \n him \n'
$ printf "%b" "$Content" > Names.txt 
$ cat Names.txt 
me 
 you 
 him
3

Quoting and using printf instead of echo might be the best habits.

First, your description doesn't match. If you have a variable with 'me \n you \n him \n' then it will not have a newline anywhere, not with echo $var, nor printf '%s' $var, nor with echo "$var" or printf '%s' "$var"

$ var='me \n you \n him \n'
$ echo $var
me \n you \n him \n

No newline, no ending newline (other than the one added by echo).

I believe that what you have is something with newlines inside which you have represented by \n. Something like:

$ var=$'me \n you \n him \n'
$ printf '%s' "$var"
me 
 you 
 him
$

And here the quoting is (very) important:

$ printf '%s' $var
meyouhim$

.........

$ echo $var meyouhim $

.........

$ echo "$var" me you him

$

.....

Note the additional newline introduced by echo? That is th eonly one removed with echo -n:

$ echo -n "$var"
me 
 you 
 him 
$

That seems to be the problem with your file, it ends on two newline characters, one from the actual $Content var and one from echo.

If that is actually the problem, then, a echo -n "$var" > Names.txt would give you a file with only one ending newline.

Or much better, do:

$ Content=$'me \n you \n him \n' 
$ printf '%s' "$Content" > Names.txt
$ cat Names.txt 
me 
 you 
 him
$