Adding text to file in linux

How do I add text to the beginning of a file in Bash?

Hi I want to prepend text to a file. For example I want to add tasks to the beginning of a todo.txt file. I am aware of echo ‘task goes here’ >> todo.txt but that adds the line to the end of the file (not what I want).

11 Answers 11

echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt 
sed -i '1s/^/task goes here\n/' todo.txt 
sed -i '1itask goes here' todo.txt 
sed -i '.bak' '1s/^/task goes here\'$'\n/g' todo.txt 
echo -e "task goes here\n$(cat todo.txt)" > todo.txt 
echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt 

the first one works great! would you mind explaining the logic? im not particularly sure how to interpret the syntax.

@user8347: Pipe ( | ) the message ( echo ‘. ‘ ) to cat which uses — (standard input) as the first file and todo.txt as the second. cat conCATenates multiple files. Send the output ( > ) to a file named temp . If there are no errors ( && ) from cat then rename ( mv ) the temp file back to the original file ( todo.txt ).

@itaifrenkel: I’d have to see what you did, but if cat receives a literal backslash n, it won’t convert it to a newline. Something else must have done that. Instead of cat , try piping into hexdump -C to see if you’re actually sending backslash and n or if it’s a newline. You could also try cat -e to show line endings.

@Kira: The 1 means do the next command only on line one of the file and the i command is insert. Look in the man page under the «Addresses» section and in the «Zero- or One- address commands» section.

A simpler option in my opinion is :

echo -e "task goes here\n$(cat todo.txt)" > todo.txt 

This works because the command inside of $(. ) is executed before todo.txt is overwritten with > todo.txt

While the other answers work fine, I find this much easier to remember because I use echo and cat every day.

EDIT: This solution is a very bad idea if there are any backslashes in todo.txt , because thanks to the -e flag echo will interpret them. Another, far easier way to get newlines into the preface string is.

echo "task goes here $(cat todo.txt)" > todo.txt 

. simply to use newlines. Sure, it isn’t a one-liner anymore, but realistically it wasn’t a one-liner before, either. If you’re doing this inside a script, and are worried about indenting (e.g. you’re executing this inside a function) there are a few workarounds to make this still fit nicely, including but not limited to:

echo 'task goes here'$'\n'"$(cat todo.txt)" > todo.txt 

Also, if you care about whether a newline gets added to the end of todo.txt , don’t use these. Well, except the second-to-last one. That doesn’t mess with the end.

printf would be a lot more consistent across platforms and should generally work more smoothly than echo -e

The moreutils have a nice tool called sponge :

echo "task goes here" | cat - todo.txt | sponge todo.txt 

It’ll «soak up» STDIN and then write to the file, which means you don’t have to worry about temporary files and moving them around.

Читайте также:  Grub восстановить linux windows

You can get moreutils with many Linux distros, through apt-get install moreutils , or on OS X using Homebrew, with brew install moreutils .

I would use tee instead of sponge which come by default on most distro echo «task goes here» | cat — todo.txt | tee todo.txt

@stevenpenny Good point. Now I remember why I didn’t suggest it originally. I came back to this answer not noticing that the output file name was the same as the input, which is why you need sponge to buffer it all before writing it back out.

You can use the POSIX tool ex :

You can create a new, temporary file.

echo "new task" > new_todo.txt cat todo.txt >> new_todo.txt rm todo.txt mv new_todo.txt todo.txt 

You might also use sed or awk . But basically the same thing happens.

Say you’re out of disk space so that new_todo.txt gets written only partially. Your solution appears to lose the original file.

@Keith Someone working on a VM who didn’t expect to need a particularly large virtual drive. Or someone moving a large file. In any case, the real argument against this is directory permissions; if you don’t have permission to create new files in the given directory, the only command that will successfully execute in your script is the rm of the original file.

If the text file is small enough to fit in memory, you don’t have to create a temporary file to replace it with. You can load it all into memory and write it back out to the file.

echo "$(echo 'task goes here' | cat - todo.txt)" > todo.txt 

It’s impossible to add lines to the beginning of the file without over writing the whole file.

As far as I’m aware, it’s only limited by the amount of memory available. I’ve filled up variables well over 100MB into memory. text=$(cat file) . Be careful to only use text though, because shell variables aren’t binary clean mywiki.wooledge.org/BashFAQ/058

You cannot insert content at the beginning of a file. The only thing you can do is either replace existing content or append bytes after the current end of file.

Any solution to your question then requires a temporary file (or buffer) to be created (on memory or on disk) which will eventually overwrite the original file.

Beware of not losing data by preserving the original file while creating the new one, should the file system happen to be full during the process. eg:

cat <(echo task go there) todo.txt >todo.txt.new && mv todo.txt.new todo.txt 

Downvoters are welcome to explain their motivation. None of the remaining answers, including the accepted one, do contradict anything in my reply.

This is difficult to parse as the < . >look like brackets, which I assume they are not. A space between the < and the ( might help?

This is not working for me. echo HOME=\»/g/Users/timregan/\» | cat — ‘F:\Program Files\Git\etc\profile’ works but cat

@dumbledad You are overthinking my reply. There is nothing for you to parse in it. A space between the < and the ( would break the syntax. Try cat <(echo HOME=\"/g/Users/timregan/\") 'F:\Program Files\Git\etc\profile'

echo 'task goes here' | cat - todo.txt | tee todo.txt 

Final answer

I wasn’t too satisfied with the answers as they felt like too much typing. I liked John Alberts his answer but couldn’t stand to type -e . Unfortunately, I accidentally read over John Alberts his echo 2 liner as well (significantly reducing the value of this answer and me 30 minutes playing around, but oh well, it happens).

In any case, I was focused on finding something that meant you only needed to type the filename and text you want to prepend.

Moreover, I was searching for something that looked aesthetically intuitive. With that I mean: the preprend needs to physically show, even if it’d be an illusion it’d have the effect of a mnemonic.

So I tried an approach with herestrings since in the right context they reduce cognitive strain (i.e. typing < 3 times doesn't require too much thinking power).

I created a file test.txt with the word «monkeys» .

You need to manually press enter yourself.

On the second line the > is from the shell itself, you don’t need to type that.

(1) What I couldn’t manage was a one liner. There seems to be no herestring combination in which I could use $() and \n . Which is why you need to press the newline manually yourself.

The command substitution $(cat file) can be replaced by the equivalent but faster $( < file) .

More typing, but I admit a bit less cognitive strain since cat is being typed twice and is more well-known than the trick of the Bash Reference Manual.

Источник

Append text to file from command line without using io redirection

this sounds like an XY problem (perlmonks.org/index.pl?node_id=542341), why do you need append without redirection?

@Joel : could be true. I asked the question for a colleague, and really don’t know what the exact problem is.

Typically useful when manipulating files with sudo (the IO are under the user’s environment), and you sometimes have a limited set of tools allowed via sudo.

5 Answers 5

If you don’t mind using sed then,

$ cat test this is line 1 $ sed -i '$ a\this is line 2 without redirection' test $ cat test this is line 1 this is line 2 without redirection

As the documentation may be a bit long to go through, some explanations :

  • -i means an inplace transformation, so all changes will occur in the file you specify
  • $ is used to specify the last line
  • a means append a line after
  • \ is simply used as a delimiter

I get sed: -i may not be used with stdin on macOS 13.3 bash shell. Probably cos of stackoverflow.com/a/21243111/259453

If you just want to tack something on by hand, then the sed answer will work for you. If instead the text is in file(s) (say file1.txt and file2.txt):

perl -e ‘open(OUT, «>>», «outfile.txt»); print OUT while (<>);’ file*.txt

N.B. while the >> may look like an indication of redirection, it is just the file open mode, in this case «append».

You can use the —append feature of tee :

cat file01.txt | tee --append bothFiles.txt cat file02.txt | tee --append bothFiles.txt 
cat file01.txt file02.txt | tee --append bothFiles.txt 

I assume the request for no redirection ( >> ) comes from the need to use this in xargs or similar. So if that doesn’t count, you can mute the output with >/dev/null .

Piping will also step out of xargs.. So not much better than >> , the best approach here is using sh -c

@Tofandel, I meant before xargs . You can pipe as much as you want before xargs ; but >> will require you to end the pipe, which then can’t continue to xargs .

You can use Vim in Ex mode:

I like the approach in this answer, but it doesn’t seem to append to the file. A simple example like this: for fidx in $(seq 1 6); do ex -sc «a|Something$» -cx test.txt; done produces text that is not ordered:cat test.txt Something2 Something1 Something3 Something4 Something5 Something6. How do I make it go to the end of the file before appending? Interestingly, it only seems to happen for the first two lines of an empty file. If I run the example multiple times everything is ordered correctly.

Try putting a $ before the a, which references the end of the file: ex -sc «$a|Something$» -cx test.txt

Источник

Command to append line to a text file without opening an editor

You can append a line of text to a file by using the >> operator:

echo "hello world" >> my_file.txt 
echo "alias list='ls -cl --group-directories-first'" >> config.fish 

I use echo myself, but be careful, if you only specify one > then the file will truncate, not append. for a safer command you can use sed: sed -i ‘$a hello world’ filename

explanation: -i will update the file (otherwise it will just print the result to stdout), $ is regex that will match the end of the file, and a appends the following text to filename.

echo «hello world» >> my_file.txt does not create a new last line with HW , but add it to the string of the last line.

Maybe «Hello World» @7wp 🙂 It’s echo that adds the line break (making it a line as opposed to just a bunch of characters). You can switch off the line break at the end with -n .

Adding to Stefano’s answer, you can also use cat :

$ cat >> config.fish alias list='ls -cl --group-directories-first' > EOF 

I often use this method but recently got caught when I pasted in a text that included some (escape) codes. It didn’t complain but when I checked the file there were chunks of pasted text missing. So use it with care!

@elmclose Sorry, which method? They work differently with respect to metacharacters. I think the second one doesn’t do anything with them, though there might be a few exceptions.

I meant EOF method. Very convenient and useful when you type or paste in readable text. But codes in my text confused the process. The file was a bash script that kept failing. Took me a while before I discovered what had happened.

There’s plenty of methods of appending to file without opening text editors, particularly via multiple available text processing utilities in Ubuntu. In general, anything that allows us to perform open() syscall with O_APPEND flag added, can be used to append to a file.

    GNU version of dd utility can append data to file with conv=notrunc oflag=append

printf "\nalias list='ls -cl --group-directories-first'\n" | dd conv=notrunc oflag=append bs=1 of=config.fish 
sed -i '$a alias list='"'"'ls -cl --group-directories-first'"'" config.fish 
 #!/usr/bin/env python3 # read bytes from stdin, append to specified file import sys with open(sys.argv[1],'ab') as f: f.write(sys.stdin.buffer.read()) 

See also:

Источник

Оцените статью
Adblock
detector