2

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.

  • 2
    why not echo -e "\n x" ? – RomanPerekhrest Feb 7 '18 at 12:29
  • 1
  • 1
    While I'm sure there is a way to do what you want (There is almost always a way), to be clear: You are asking for a way to bypass the rules of the shell in order to make it easier for you to read? What about the people that come after you and read it? – Jesse_b Feb 7 '18 at 12:39
  • 1
    @RomanPerekhrest it makes a single space before x in the second line... I don't want that single space before x. I want space only in the command itself for ease of read. – user9303970 Feb 7 '18 at 13:06
  • 2
    The same result could be had with { echo; echo x; } >file. – Kusalananda Feb 7 '18 at 13:17
3

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.

  • Nice! Thanks. What's the %s in printf? I didn't find in man printf. – user9303970 Feb 7 '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 7 '18 at 13:29
  • 1
    What Kusalananda said ^^. I'm not great with printf but the bash-hackers wiki on printf is a good reference for me anyway. – Jesse_b Feb 7 '18 at 13:31
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"
  • yes, printf "%s" arg arg ... is the answer. – glenn jackman Feb 7 '18 at 13:39
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
  • Of course I had finished typing my answer before I saw this one. – G-Man Feb 7 '18 at 17:51
  • Thumbed for the rich, didactic answer. – user9303970 Feb 8 '18 at 0:44
  • G-Man, as you suggested I checked the bytes of the files. Indeed there was a change of one byte. Without any of the two changes, at the start, the file had 2188 bytes. With \n%s it had 2217. I then changed it to \n%s\n and got 2218, so that extra \n%s\n is all the change. I thank you Jesse_b and G-Man for your help. – user9303970 Feb 8 '18 at 0:59
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 "$*"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.