Way 1: Escape instances of \
that you don't want to escape other characters.
Based on the contents of your string, you probably want:
echo -e 'writes (>> appends) in note.txt this text\non 2 lines (with "-e" and "\\n" help)' >> note.txt
The text this appends to note.txt
is:
writes (>> appends) in note.txt this text
on 2 lines (with "-e" and "\n" help)
The changes are:
- You had
/n
where it looked like you wanted a line break. So I changed that to \n
.
- In the text
with "-e" and "\n"
, the \
is intended to be printed literally rather than to combine with the n
following it and produce a newline. So I quoted (escaped) \
with another \
. If \n
produces a new line, \\n
produces \n
.
I replaced the outer double quotes ("
) with single quotes ('
). You wanted the "
characters around -e
and \n
to be printed literally, but instead they ended and restarted quoting, preventing them from being printed and causing \n
to actually be printed as n
(because an unquoted \n
is processed before being passed to echo
). An alternative solution would have been to write \"
for the inside "
characters. But there was no reason to enclose the whole thing in double quotes--single quotes are usually preferable in cases where either can be used.
The other change--which was not a change in the final command but was a change I made just while working on it--was that I removed the >> note.txt
redirection until I knew I had the command right. By sending output to the terminal, I was immediately able to see what the effect was. I re-added the redirection when I was done.
That's stylistically closest to what you already had, but it's not the only way to do it.
Way 2: Separate echo
commands for separate lines, instead of using -e
.
Since the only sequence you want treated specially by echo is the \n
(between text
and on
), you can just use two separate echo
commands and (as muru may be suggesting) not use -e
.
Here are two ways of redirecting the output of multiple commands:
Two separate redirections, one for each command.
echo 'writes (>> appends) in note.txt this text' >> note.txt
echo 'on 2 lines (with "-e" and "\n" help)' >> note.txt
If the filename is long or you're writing a script and only want to have to change it in one place, you can assign it to a variable:
out="/home/ek/Documents/long name that can have spaces as it's quoted/note.txt"
echo 'writes (>> appends) in note.txt this text' >> "$out"
echo 'on 2 lines (with "-e" and "\n" help)' >> "$out"
A single redirection applied to a compound command composed of the two commands.
{
echo 'writes (>> appends) in note.txt this text'
echo 'on 2 lines (with "-e" and "\n" help)'
} >> note.txt
You can put that on one line if you like, but if there's no newline before the closing brace (}
), a semicolon (;
) must precede it:
{ echo 'writes (>> appends) in note.txt this text'; echo 'on 2 lines (with "-e" and "\n" help)'; } >> note.txt
Way 3: Pass a literal \n
to echo
instead of using -e
.
Real newlines can appear inside quotes (single or double) and are interpreted literally:
echo 'writes (>> appends) in note.txt this text
on 2 lines (with "-e" and "\n" help)' >> note.txt
Because the first line ends inside quotes, the shell doesn't take it as the end of the command, but instead continues reading.
If you do want to fit it on a single line, you can use $'\n'
, which expands to a newline. This is expanded by the shell before being passed to the echo
command, so it should not be quoted.
echo 'writes (>> appends) in note.txt this text'$'\n''on 2 lines (with "-e" and "\n" help)' >> note.txt
Way 4: Use printf
printf
is very powerful; there are a number of ways you could use it to solve this problem. Since I am presenting this as a distinct solution from the others, here's a good way to use it in a way you cannot use echo
:
printf '%s\n%s\n' 'writes (>> appends) in note.txt this text' 'on 2 lines (with "-e" and "\n" help)' >> note.txt
The general syntax for printf
is printf format args...
(where args...
means zero or more additional command-line arguments). The format string above, %s\n%s\n
, means:
%s
: consume and print the next unused (i.e., first) argument in args...
(i.e., your 1st line).
\n
: print a newline.
%s
: consume and print the next unused (i.e., second) argument in args...
(i.e., your 2nd line).
\n
: print a newline.
When there are more arguments after the format string than the format string calls for, the printf
command starts over from the beginning of the format string. Thus, while less self-documenting, you could actually write just '%s\n'
(instead of '%s\n%s\n'
) for the format string, and it would produce the same output in this case.
I will not attempt to broadly document printf
here. Instead, see:
Way 5: Use cat
and a here document.
This way is especially valuable when there's a lot of input, and when scripting. If you're using the shell interactively rather than writing a script, you can use this, but please consider Way 6 below first.
While echo
and printf
print text based on the contents of their command-line arguments, cat
prints the contents of its input files (as specified on the command line) or, if given none (or passed -
), its standard input.
With no redirections, standard input is what you type on a program's controlling terminal. Here documents are a special kind of redirection. Lines are collected until a specified keyword (I've used EOF
) appears by itself on a line. Then the lines up to but not including EOF
(or whatever you used) are given as standard input to the command being run.
cat >> note.txt << EOF
writes (>> appends) in note.txt this text
on 2 lines (with "-e" and "\n" help)
EOF
One of the differences between quoting with "
and '
is that most expansions and substitutions with $
(e.g., $varname
) are performed in double quotes, but none are in single quotes. There are also two ways to use here documents, based on whether $
(and also `
and \
) are to be given special meaning or treated literally.
In this case, it doesn't matter--$
and `
don't appear, and \
is only treated specially in a here document when it escapes a shell metacharacter (not n
). Just as in single and double quoted expressions, both ways treat \n
literally. (Remember, you had to use a special feature of echo
, turned on by -e
, to get \n
treated specially.)
But so you know for other applications:
- The way shown above will perform expansions and substitutions, treating
$
, `
, and \
specially when they appear in a context where their special meaning applies.
- To cause all text to be treated literally, quote all or part of the word appearing to the right of
<<
with '
, "
, \
, or a combination thereof (e.g., cat >> note.txt << 'EOF'
).
Way 6: Use cat
without any input redirection.
If you're using the shell interactively, by default the shell's standard input is taken from your terminal. When you then run a program, by default that program's standard input is taken from your terminal too. (This may be changed by input redirections, of course.)
So if you're running a command interactively and want to use cat
with >>
or >
output redirection to send data to a file, you don't need any input redirection. Just enter:
cat >> note.txt
writes (>> appends) in note.txt this text
on 2 lines (with "-e" and "\n" help)
^D
In place of ^D
, don't enter a literal ^D
. Instead, press Ctrl+D. That signals to your terminal that it should report end of file (i.e., that when the running program asks for more input, it is told that there is none left, just as if it had reached the end of a regular file stored on disk). When cat
sees there's no more input, it exits, and you are returned to the shell.
If you're writing a script, Way 6 will not work, because bash reads commands from a file but standard input is still (typically) a something else, such as your terminal.
One notable difference between using cat
with a here document and using cat with no input redirection, even when standard input is your terminal, is that:
cat >> note.txt
writes one line at a time to note.txt
. Each time you press Enter, a line is written to note.txt
.
cat >> note.txt << EOF
takes all input up to the EOF
line, then appends it to note.txt
. If you interrupt the input by pressing Ctrl+C, nothing is written (and if note.txt
didn't exist already, it is not even created).