[linux] How to insert a text at the beginning of a file?

So far I've been able to find how to add a line at the beginning of a file but that's not exactly what I want. I'll show it on a example

File content

some text at the beginning

Result

<added text> some text at the beginning

It's similar but I don't want to create any new line with it...

I would like to do this with sed if possible.

This question is related to linux bash sed

The answer is


sed can operate on an address:

$ sed -i '1s/^/<added text> /' file

What is this magical 1s you see on every answer here? Line addressing!.

Want to add <added text> on the first 10 lines?

$ sed -i '1,10s/^/<added text> /' file

Or you can use Command Grouping:

$ { echo -n '<added text> '; cat file; } >file.new
$ mv file{.new,}

PROBLEM: tag a file, at the top of the file, with the base name of the parent directory.

I.e., for

/mnt/Vancouver/Programming/file1

tag the top of file1 with Programming.

SOLUTION 1 -- non-empty files:

bn=${PWD##*/}    ## bn: basename

sed -i '1s/^/'"$bn"'\n/' <file>

1s places the text at line 1 of the file.

SOLUTION 2 -- empty or non-empty files:

The sed command, above, fails on empty files. Here is a solution, based on https://superuser.com/questions/246837/how-do-i-add-text-to-the-beginning-of-a-file-in-bash/246841#246841

printf "${PWD##*/}\n" | cat - <file> > temp && mv -f temp <file>

Note that the - in the cat command is required (reads standard input: see man cat for more information). Here, I believe, it's needed to take the output of the printf statement (to STDIN), and cat that and the file to temp ... See also the explanation at the bottom of http://www.linfo.org/cat.html.

I also added -f to the mv command, to avoid being asked for confirmations when overwriting files.

To recurse over a directory:

for file in *; do printf "${PWD##*/}\n" | cat - $file > temp && mv -f temp $file; done

Note also that this will break over paths with spaces; there are solutions, elsewhere (e.g. file globbing, or find . -type f ... -type solutions) for those.

ADDENDUM: Re: my last comment, this script will allow you to recurse over directories with spaces in the paths:

#!/bin/bash

## https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively-to-delete-files-with-certain-extensi

## To allow spaces in filenames,
##   at the top of the script include: IFS=$'\n'; set -f
##   at the end of the script include: unset IFS; set +f

IFS=$'\n'; set -f

# ----------------------------------------------------------------------------
# SET PATHS:

IN="/mnt/Vancouver/Programming/data/claws-test/corpus test/"

# https://superuser.com/questions/716001/how-can-i-get-files-with-numeric-names-using-ls-command

# FILES=$(find $IN -type f -regex ".*/[0-9]*")        ## recursive; numeric filenames only
FILES=$(find $IN -type f -regex ".*/[0-9 ]*")         ## recursive; numeric filenames only (may include spaces)

# echo '$FILES:'                                      ## single-quoted, (literally) prints: $FILES:
# echo "$FILES"                                       ## double-quoted, prints path/, filename (one per line)

# ----------------------------------------------------------------------------
# MAIN LOOP:

for f in $FILES
do

  # Tag top of file with basename of current dir:
  printf "[top] Tag: ${PWD##*/}\n\n" | cat - $f > temp && mv -f temp $f

  # Tag bottom of file with basename of current dir:
  printf "\n[bottom] Tag: ${PWD##*/}\n" >> $f
done

unset IFS; set +f

There is a very easy way:

echo "your header" > headerFile.txt
cat yourFile >> headerFile.txt

To add a line to the top of the file:

sed -i '1iText to add\'

With the echo approach, if you are on macOS/BSD like me, lose the -n switch that other people suggest. And I like to define a variable for the text.

So it would be like this:

Header="my complex header that may have difficult chars \"like these quotes\" and line breaks \n\n "

{ echo "$Header"; cat "old.txt"; } > "new.txt"
mv new.txt old.txt

Another solution with aliases. Add to your init rc/ env file:

addtail () { find . -type f ! -path "./.git/*" -exec sh -c "echo $@ >> {}" \; }
addhead () { find . -type f ! -path "./.git/*" -exec sh -c  "sed -i '1s/^/$@\n/' {}" \; }

Usage:

addtail "string to add at the beginning of file"
addtail "string to add at the end of file"

Just for fun, here is a solution using ed which does not have the problem of not working on an empty file. You can put it into a shell script just like any other answer to this question.

ed Test <<EOF
a

.
0i
<added text>
.
1,+1 j
$ g/^$/d
wq
EOF

The above script adds the text to insert to the first line, and then joins the first and second line. To avoid ed exiting on error with an invalid join, it first creates a blank line at the end of the file and remove it later if it still exists.

Limitations: This script does not work if <added text> is exactly equal to a single period.


Use subshell:

echo "$(echo -n 'hello'; cat filename)" > filename

Unfortunately, command substitution will remove newlines at the end of file. So as to keep them one can use:

echo -n "hello" | cat - filename > /tmp/filename.tmp
mv /tmp/filename.tmp filename

Neither grouping nor command substitution is needed.


If you want to add a line at the beginning of a file, you need to add \n at the end of the string in the best solution above.

The best solution will add the string, but with the string, it will not add a line at the end of a file.

sed -i '1s/^/your text\n/' file

To insert just a newline:

sed '1i\\'

Note that on OS X, sed -i <pattern> file, fails. However, if you provide a backup extension, sed -i old <pattern> file, then file is modified in place while file.old is created. You can then delete file.old in your script.


my two cents:

sed  -i '1i /path/of/file.sh' filename

This will work even is the string containing forward slash "/"


Hi with carriage return:

sed -i '1s/^/your text\n/' file

echo -n "text to insert " ;tac filename.txt| tac > newfilename.txt

The first tac pipes the file backwards (last line first) so the "text to insert" appears last. The 2nd tac wraps it once again so the inserted line is at the beginning and the original file is in its original order.


If the file is only one line, you can use:

sed 's/^/insert this /' oldfile > newfile

If it's more than one line. one of:

sed '1s/^/insert this /' oldfile > newfile
sed '1,1s/^/insert this /' oldfile > newfile

I've included the latter so that you know how to do ranges of lines. Both of these "replace" the start line marker on their affected lines with the text you want to insert. You can also (assuming your sed is modern enough) use:

sed -i 'whatever command you choose' filename

to do in-place editing.


You can use cat -

printf '%s' "some text at the beginning" | cat - filename

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to sed

Retrieve last 100 lines logs How to replace multiple patterns at once with sed? Insert multiple lines into a file after specified pattern using shell script Linux bash script to extract IP address Ansible playbook shell output remove white space from the end of line in linux bash, extract string before a colon invalid command code ., despite escaping periods, using sed RE error: illegal byte sequence on Mac OS X How to use variables in a command in sed?