Unix command to prepend text to a file

邮差的信 提交于 2019-11-27 17:16:29
Prince John Wesley
sed -i.old '1s;^;to be prepended;' inFile
  • -i writes the change in place and take a backup if any extension is given. (In this case, .old)
  • 1s;^;to be prepended; substitutes the beginning of the first line by the given replacement string, using ; as a command delimiter.
shime
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt

Process Substitution

I'm surprised no one mentioned this.

cat <(echo "before") text.txt > newfile.txt

which is arguably more natural than the accepted answer (printing something and piping it into a substitution command is lexicographically counter-intuitive).

...and hijacking what ryan said above, with sponge you don't need a temporary file:

sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt

EDIT: Looks like this doesn't work in Bourne Shell /bin/sh


Here String

Using a here-string - <<< (again, you need bash), you can do:

<<< "to be prepended" < text.txt | sponge text.txt

This is one possibility:

(echo "to be prepended"; cat text.txt) > newfile.txt

you'll probably not easily get around an intermediate file.

Alternatives (can be cumbersome with shell escaping):

sed -i '0,/^/s//to be prepended/' text.txt

This will work to form the output. The - means standard input, which is provide via the pipe from echo.

echo -e "to be prepended \n another line" | cat - text.txt

To rewrite the file a temporary file is required as cannot pipe back into the input file.

echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
ryan

Prefer Adam's answer

We can make it easier to use sponge. Now we don't need to create a temporary file and rename it by

echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt

Probably nothing built-in, but you could write your own pretty easily, like this:

#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"

Something like that at least...

In some circumstances prepended text may available only from stdin. Then this combination shall work.

echo "to be prepended" | cat - text.txt | tee text.txt

If you want to omit tee output, then append > /dev/null.

Solution:

printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt

Note that this is safe on all kind of inputs, because there are no expansions. For example, if you want to prepend !@#$%^&*()ugly text\n\t\n, it will just work:

printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt

The last part left for consideration is whitespace removal at end of file during command substitution "$(cat file.txt)". All work-arounds for this are relatively complex. If you want to preserve newlines at end of file.txt, see this: https://stackoverflow.com/a/22607352/1091436

mklement0

If it's acceptable to replace the input file:

Note: Doing so may have unexpected side effects, notably replacing a symlink with a regular file, possibly ending up with different permissions on the file, and changing the file's creation (birth) date.

sed -i, as in Prince John Wesley's answer, tries to at least restore the original permissions, but the other limitations apply.

 { printf 'line 1\nline 2\n'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt

Note: Using a group command { ...; ... } is more efficient than using a subshell ((...; ...)).


If the input file should be edited in place (preserving its inode with all its attributes):

Using the venerable ed POSIX utility:

Note: ed invariably reads the input file as a whole into memory first.

ed -s text.txt <<'EOF' 
1i
line 1
line 2
.
w
EOF
  • -s suppressed ed's status messages.
  • Note how the commands are provided to ed as a multi-line here-document (<<'EOF' ... EOF), i.e., via stdin.
  • 1i makes 1 (the 1st line) the current line and starts insert mode (i).
  • The following lines are the text to insert before the current line, terminated with . on its own line.
  • w writes the result back to the input file (for testing, replace w with ,p to only print the result, without modifying the input file).

Another way using sed:

sed -i.old '1 {i to be prepended
}' inFile

If the line to be prepended is multiline:

sed -i.old '1 {i\ 
to be prepended\
multiline
}' inFile

As tested in Bash (in Ubuntu), if starting with a test file via;

echo "Original Line" > test_file.txt

you can execute;

echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt

or, if the version of bash is too old for $(), you can use backticks;

echo "`echo "New Line"; cat test_file.txt`" > test_file.txt

and receive the following contents of "test_file.txt";

New Line
Original Line

No intermediary file, just bash/echo.

Another fairly straight forward solution is:

    $ echo -e "string\n" $(cat file)

If you like vi/vim, this may be more your style.

printf '0i\n%s\n.\nwq\n' prepend-text | ed file
# create a file with content..
echo foo > /tmp/foo
# prepend a line containing "jim" to the file
sed -i "1s/^/jim\n/" /tmp/foo
# verify the content of the file has the new line prepened to it
cat /tmp/foo

I didn't really like any of the answers here, so I built my own command: pre.

Install with go:

go get -u github.com/Flaque/pre

Prepend some text from stdin to a file with:

echo "some at the start" | pre myFile.txt | sponge myFile.txt

The command doesn't write in place, it just outputs to stdout, so you'll need the sponge from moreutils on the end to save the file.

I'd recommend defining a function and then importing and using that where needed.

prepend_to_file() { 
    file=$1
    text=$2

    if ! [[ -f $file ]] then
        touch $file
    fi

    echo "$text" | cat - $file > $file.new

    mv -f $file.new $file
}

Then use it like so:

prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"

Your file contents will then be:

This is second
This is first

I'm about to use this approach for implementing a change log updater.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!