3

I use echo to print two strings into a file in either of these two commands:

echo -e "\n""x" >> ~/file
echo -e "\n" "x" >> ~/file

The first result is:


x

The second result is:


 x

I assume you didn't miss the extra space.

I most desire that the second command would behave like the first one because the extra space between "\n" and "x" makes it more comfortable to read the command.

Given it's not possible naturally in Bash 4.3.48(1), is there any syntax that will allow it or at least, come close to it?

The main goal is to have a spacing, or at least some placeholder/separator, that will give me a some kind of separation between the two strings, for more comfortable reading, but without having that extra space above.

Please show any way you know. I'm open to use something else than echo (though I'd prefer to avoid here-string).


Note, I used the term "string" for "\n". I'm not sure it's correct here, but it's the best term I have to describe that.

4 Answers4

4

You can do this with the printf command:

printf '\n%s\n' 'x' >file

With echo, I was able to accomplish this using tr to delete whitespace:

echo -e '\n x' | tr -d ' ' >file

Can also be written as (but please don't):

echo -e '\n' 'x' | tr -d ' ' >file

Results:

$ cat file

x

I suppose it could also easily be argued that these will actually make your command harder to read.

jesse_b
  • 37,005
  • Nice! Thanks. What's the %s in printf? I didn't find in man printf. – Arcticooling Feb 07 '18 at 13:17
  • 2
    @user9303970 It's a placeholder for a string which will be inserted from the arguments after the format string (\n%s\n). man printf probably documents the C library function printf(), but it's using the same format string placeholders as printf in the shell. %s is for "a string" while %d is for "a decimal integer", etc. One could also specify field widths, left or right alignments etc. – Kusalananda Feb 07 '18 at 13:29
3

If the key point is visually separating the two strings (\n and x, here) in the script source, I suppose you could put them in variables:

str1='\n'
str2='x'
echo -e "$str1$str2" >> file

The parameter expansions are of course back-to-back, but the strings themselves aren't.

Or with printf, but adding the tailing newline must be done separately:

{ printf %s $'\n' 'x'; echo; } >> file

%s of course doesn't expand backslash-escapes from the argument string, but in Bash we can use the $'...' ANSI-C quoting that does. echo to get the final newline.

Or define a function to do what you want ("$*" concatenates the arguments to the function, without delimiter since IFS was cleared here):

output() { local IFS=; echo -e "$*"; }
output "\n" "x"
ilkkachu
  • 138,973
1

You can use the %b (interpret backquoted arguments) of bash printf:

$ printf  %b  \\n  x  >> file

Of course, you can quote the \n:

$ printf  %b  '\n'  x  >> file

But be very careful with what you feed to printf as any backquoted value instead of x will be interpreted by printf.

Or, since you are using bash, it allows a newline to be generated with $'\n':

$ printf '%s' $'\n' x >>file

Somewhat safer than %b.

Or, if you want a variable:

$ nl=$'\n'
$ printf '%s' "$nl" x >> file

Or you can define a function:

$ separate() { local IFS=; printf %b "$*"; }
$ separate '\n' 'x' '*'

The local IFS= will ensure the arguments are joined together (no spaces in between) by "$*"

1

If the objective is specifically to write a newline and an x (and another newline?) to a file, without having n and x appear consecutively (i.e., nx) in your command (and without including an undesired space in your output), a very simple approach is

{ echo; echo "x";} >> file

(to write newline, x, newline), or

{ echo; echo -n "x";} >> file

(to write newline and x, but no newline at the end).  You can also use parentheses instead of braces for grouping:

(echo; echo "x") >> file

Note that, with braces, you must have whitespace (space(s), tab(s) and/or newline(s)) after the opening {, and you must have a ; (and/or newline(s)) before the closing }.  Or you can do two totally separate (not grouped) commands that do redirection independently:

echo     >> file
echo "x" >> file

Or use Jesse_b’s answer:

printf '\n%s\n' 'x' >> file

(to write newline, x, newline), or

printf '\n%s'   'x' >> file

(to write newline and x, but no newline at the end).


But if the objective is more general — to write a bunch of strings (with no intervening spaces), while separating them by spaces on the command line, consider

printf '%b' string …

where %b is the conversion format to print a string with \ sequences interpreted (in contrast to %s, which prints strings literally).  For example,

printf '%b' '\n' foo '\t' bar

will write newlinefootabbar; i.e.,

 
foo     bar
(with no newline at the end).  You could also say
printf '%b%b%b%b' '\n' foo '\t' bar

but you don’t need to; the format will be applied as many times as necessary to display all the arguments.  Therefore, if you want to add a newline at the end,

printf '%b\n' '\n' foo '\t' bar

will not work; it will add a newline after each argument.  You can do

printf '%b' '\n' foo '\t' bar '\n'

(adding a newline as a final argument), or

printf '%b%b%b%b\n' '\n' foo '\t' bar

(counting the arguments), or

{ printf '%b' '\n' foo '\t' bar; echo;}

Yet another approach, if you’re using bash, is

printf '%s' $'\n' foo $'\t' bar

using bash’s $'text…' notation to interpret \ sequences.  Applying this to the original question, we would get

printf '%s' $'\n' x