15

I always do this to append text to a file

echo "text text text ..." >> file
# or
printf "%s\n" "text text text ..." >> file

I wonder if there are more ways to achieve the same, more elegant or unusual way.

annahri
  • 2,075
  • 3
    As I already said, it's not only that. echo "a\nb" will print something different than printf "%s\n" "a\nb", in ~all the shells but bash. You cannot assume that the two are similar. –  Feb 14 '20 at 05:47
  • 1
    Note that you can group commands together (a ; b ; c) >> file – Thorbjørn Ravn Andersen Feb 15 '20 at 13:44

6 Answers6

29

I quite like this one, where I can set up a log file at the top of a script and write to it throughout without needing either a global variable or to remember to change all occurrences of a filename:

exec 3>> /tmp/somefile.log
...

echo "This is a log message" >&3
echo "This goes to stdout"
echo "This is written to stderr" >&2

The exec 3>dest construct opens the file dest for writing (use >> for appending, < for reading - just as usual) and attaches it to file descriptor #3. You then get descriptor #1 for stdout, #2 for stderr, and this new #3 for the file dest.

You can join stderr to stdout for the duration of a script with a construct such as exec 2>&1 - there are lots of powerful possibilities. The documentation (man bash) has this to say about it:

exec [-cl] [-a name] [command [arguments]] If command is specified, it replaces the shell. [...] If command is not specified, any redirections take effect in the current shell [...].

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
14

Here are few other ways to append text to a file.

  1. Using tee

    tee -a file <<< "text text text ..."
    
  2. Using awk

    awk 'BEGIN{ printf "text text text ..." >> "file" }'
    
  3. Using sed

    sed -i '$a text text text ...' file
    sed -i -e "\$atext text text ..." file
    

Sources:

muru
  • 72,889
  • 2
    sed -i does not so much append as overwrite with an extended version. Normally not much of an issue, but it can be if the file is sparse, linked, or actively being read. – David G. Feb 16 '20 at 12:44
11

Using a here-document approach:

cat <<EOF >> file
> foo
> bar
> baz
> EOF

Tests:

$ cat file
aaaa
bbbb

$ cat <<EOF >> file
> foo
> bar
> baz
> EOF

$ cat file
aaaa
bbbb
foo
bar
baz
Paulo Tomé
  • 3,782
5

See dd(1) man page:

dd conv=notrunc oflags=append bs=4096 if=myNewData of=myOldFile
Paul_Pedant
  • 8,679
  • This is creative, but can you use a line of string instead of an input file? – annahri Feb 14 '20 at 14:23
  • @annahri yes certainly, dd conv=notruct oflag=append of=destination <<<'Some string of text' – Chris Davies Feb 14 '20 at 15:42
  • 1
    @roaima that's shell dependent though. Not all shells support the <<< herestring construct. I have no idea what dd would do in those cases, would it be safe? – terdon Feb 15 '20 at 16:04
  • @terdon I believe that the here-string construct is like feeding dd from any other file descriptor (but I've not checked the source). On that assumption, I would expect dd to be as safe as with any other similar invocation. echo 'Some string of text or printf if you prefer' | dd conv=notrunc oflag=append of=destination, etc. – Chris Davies Feb 15 '20 at 16:12
  • @roaima sure, with shells that support <<<, it should be perfectly safe. I just wonder what happens with shells that don't. Will dd simply get no input and, if so, not write anything? Will it write an empty string? Or a NULL? I guess it would do nothing, but I was just idly wondering since I don't know. – terdon Feb 15 '20 at 16:14
  • 1
    @annahri. My bad: I scrolled down under "Each CONV symbol may be:" on the man page, and missed the bit where the list changes to "Each FLAG symbol may be:". – Paul_Pedant Feb 15 '20 at 17:20
  • 1
    I tested dd with <<< in dash. It throws "Syntax error: redirection unexpected" with status 2, so dd itself is not even invoked. – Paul_Pedant Feb 15 '20 at 17:37
  • dash and other POSIX shells does not have a herestring only a heredoc so it stands to reason that if dd accepts input from stdin it should work with a heredoc on POSIX shells, see https://paste.opensuse.org/view/raw/14083760 – Jetchisel Feb 15 '20 at 21:04
  • The shell performs redirection regardless if you have it in the beginning,middle,last part of the code/script before any commands/expansion gets executed, in this case the herestring <<< – Jetchisel Feb 15 '20 at 21:11
  • @jetchisel. In your example containing >>outputfile, I don't see that dd needs either the notrunc or append options. It (dd) just inherits a stream already opened in append mode, and it does not even know the filename. – Paul_Pedant Feb 15 '20 at 23:00
  • @Paul_Pedant indeed, i stand corected. dd <<'EOF' >> file literal newlinehere 'text hereEOF` is enough. – Jetchisel Feb 15 '20 at 23:05
  • @jetchisel. Actually, showing these options is probably a good idea, even if not required here. They cause no harm. They show intent. They protect functionality if somebody changes to of=myFile without due care. dd is obscure in places, so I never use short-form options. – Paul_Pedant Feb 16 '20 at 15:10
4

Using the Unix file editors. Both GNU and BSD version.

Using ed(1) with printf

printf '%s\n' '$a' 'foo bar baz' . w | ed -s file.txt

The bash specific but more cryptic syntax using the $' ' shell quoting and a herestring

ed -s file.txt <<< $'$a\nfoo bar baz\n.\nw'

Using ex(1) with printf

printf '%s\n' '$a' 'foo bar baz' . x | ex -s file.txt

The bash specific but more cryptic syntax $' ' shell quoting and a herestring

ex -s file.txt <<< $'$a\nfoo bar baz\n.\nx'
Jetchisel
  • 1,264
  • 1
    ed, ex, and other text editors do not so much append as overwrite with an extended version. Normally not much of an issue, but it can be if the file is sparse, linked, or actively being read. – David G. Feb 16 '20 at 12:51
  • @DavidG. Thank you for that wonderful comment. – Jetchisel Feb 16 '20 at 13:42
2
cat >> file
first line
second line
...
last line

Hit Enter at the last line then Ctrl + D.

GAD3R
  • 66,769