16

I can do cat file.txt to get the contents of a file but I also want to tack on a final line of my own choosing.

I tried piping (cat file.txt ; echo "My final line") | but only the final line is getting passed through the pipe. How can I join the cat and final line?

Edit for a point of clarification: I do not wish to modify the file itself. I am aware that if this were the case I could do echo "My final line" >> file.txt or echo "My final line" | tee -a file.txt but I am only trying to do the append within the context of this particular command so I can pipe in the concatenation of file.txt and "My final line".

4
  • 1
    Maybe something like echo "My final line" >> file.txt?
    – edwinksl
    Oct 24, 2017 at 14:06
  • I don't want to actually append the line to the file object, just in the command / piping. I already know that I can append the line with >> if I wanted to edit the file itself.
    – DoubleBass
    Oct 24, 2017 at 14:09
  • 11
    Have you accidentally erased file.txt? Your pipe snippet should work.
    – Bracken
    Oct 24, 2017 at 14:15
  • @DoubleBass: Mathieu Mitchell's answer is a better one, as it doesn't modify the file (either in-memory or on disk), but instead utilizes a feature of a built-in command. Oct 24, 2017 at 17:26

5 Answers 5

38

You can leverage cat's ability to read from stdin combined with it's ability to read multiple files to achieve this.

~$ cat file.txt
Hello from file.txt

~$ echo "My final line" | cat file.txt -
Hello from file.txt
My final line

You can also prepend a line, as such:

~$ echo "My final line" | cat - file.txt
My final line
Hello from file.txt

Note that you are not limited to a single line. cat will read from stdin until it reaches EOF. You can pass the output from curl, for example, to prepend or append to the output of cat.

~$ curl -s http://perdu.com | cat file.txt -
Hello from file.txt
<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1><h2>Pas de panique, on va vous aider</h2><strong><pre>    * <----- vous &ecirc;tes ici</pre></strong></body></html>
2
  • 1
    (cat file.txt ; echo "My final line") | … would also do it. But using cat for what it was designed for is better +1. Oct 24, 2017 at 21:30
  • @ctrl-alt-delor: Sub-shells also have the disadvantage of an additional process to fork which is relatively expensive. Try for example echo "$$" "$BASHPID" | head -q -n 1 /proc/mounts - | cat vs. ( head -q -n 1 /proc/mounts; echo "$$" "$BASHPID" ) | cat or even { head -q -n 1 /proc/mounts; echo "$$" "$BASHPID"; } | cat. Oct 25, 2017 at 12:48
15

For appending a line to a file, you can just use shell append redirection operator, >> (the file will be open(2)-ed with O_APPEND flag):

echo 'My final line' >>file.txt

Now, if you want just to view the content of the file with a final line appended, i would use cat with two arguments:

  • First, your file obviously, let's say file.txt
  • Second argument would be the string of your choice, and to pass the string as a filename (as cat only deals with files) you can leverage process substitution, <(), which would return a file descriptor (/proc/self/fd/<fd_number>).

Putting these together:

cat file.txt <(echo 'My final line')

If you want the output to be paged, assuming less is your favorite pager:

less file.txt <(echo 'My final line')
3
  • <() works for bash, but what other shells does it work for? Ksh? Dash?
    – jpaugh
    Oct 24, 2017 at 17:26
  • 1
    @jpaugh ksh, zsh -- Yes, dash -- No.
    – heemayl
    Oct 24, 2017 at 17:58
  • This modifies the original. Oct 24, 2017 at 21:31
14
sed -e '$aMy final line' file.txt

From man sed the option -e

-e script, --expression=script
    add the script to the commands to be executed

$ matches the last line and a appends the string.

If you wanted to permanently append the line to the file, use -i

-i[SUFFIX], --in-place[=SUFFIX]
    edit files in place (makes backup if SUFFIX supplied)

Changing the command to

sed -i -e '$aMy final line' file.txt
1
  • 1
    Use single quotes and you don't need the backslash.
    – Wildcard
    Oct 25, 2017 at 4:10
11

It was already clarified in the comments to the question, but adding it again as an answer here.

The command noted in the question,

(cat file.txt ; echo "My final line") | other command

works as is expected – all the output from the subshell formed by the parentheses is piped to the second command.

If the file doesn't end with a new line, the echoed string is appended to the last line – this is common with all the other solutions here, and can be solved by adding another (empty) echo before.

2
  • 1
    If the file doesn't end with a newline, I'd use awk: awk 1 file.txt; echo "My final line". awk 1 file is a nice trick to compensate for missing EOL at the end of the file.
    – muru
    Oct 25, 2017 at 3:29
  • If the file doesn't end with a new line, you can also just use echo "\nMy final line" without having to depend on awk
    – fregante
    May 31, 2019 at 8:04
0

Lots of good answers here but in my case I just wanted to append a newline to some stdout, by tacking a command onto the end of the pipeline. This achieves that:

$CMD_OR_COMMANDS | cat - <(echo)

To fit the original example:

cat file.txt | cat - <(echo "My final line")

Which is admittedly a verbose way of accomplishing the thing, but the key is that this pattern might fit more of your needs, since it works on anything that produces stdout.

New contributor
billkw is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

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.