Reputation: 15834
So far I've been able to find out how to add a line at the beginning of a file but that's not exactly what I want. I'll show it with an 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.
Upvotes: 341
Views: 489409
Reputation: 1
find . -name "*prod*" -exec sed -i '1i\line1\n Line2\n Line3\n' {} \;
I use it to resolve this.
Upvotes: 0
Reputation: 1437
my two cents:
sed -i '1i /path/of/file.sh' filename
where /path/of/file.sh
is the text you want to add.
This will work even if the string contains a forward slash "/"
Upvotes: 14
Reputation: 21
thanks to all the top answers above, just a small hint:
for the sed
approach, if you want to pass a variable while going to a newline, like what I've wanted to do with my /etc/hosts
file, don't forget to use double quotes "
sed -i "1s/^/127.0.0.1 $HOSTNAME \n/" /etc/hosts
Upvotes: 1
Reputation: 165
cat
concatenates multiple files. <()
sends output of a command as a file. echo doesn't add new lines with -n switch. head command with -c switch can remove trailing newline in files. Combining all these, we can insert text at the beginning and end of a file without any new lines by,
cat <(echo -n "line before the file") <(head -c -1 file.txt) <(echo -n "line after the file")
Upvotes: 1
Reputation: 275
TL;dr -
Consider using ex
. Since you want the front of a given line, then the syntax is basically the same as what you might find for sed
but the option of "in place editing" is built-in.
I cannot imagine an environment where you have sed
but not ex
/vi
, unless it is a MS Windows box with some special "sed.exe", maybe.
sed
& grep
sort of evolved from ex
/ vi
, so it might be better to say sed
syntax is the same as ex
.
You can change the line number to something besides #1 or search for a line and change that one.
source=myFile.txt
Front="This goes IN FRONT "
man true > $source
ex -s ${source} <<EOF
1s/^/$Front/
wq
EOF
$ head -n 3 $source
This goes IN FRONT TRUE(1) User Commands TRUE(1)
NAME
Long version, I recommend ex
(or ed
if you are one of the cool kids).
I like ex
because it is portable, extremely powerful, allows me to write in-place, and/or make backups all without needing GNU (or even BSD) extensions.
Additionally, if you know the ex
way, then you know how to do it in vi
- and probably vim
if that is your jam.
Notice that EOF
is not quoted when we use "i"nsert and using echo
:
str="+++ TOP +++" && ex -s <<EOF
r!man true
1i
`echo "$str"`
.
"0r!echo "${str}"
wq! true.txt
EOF
0r!echo "${str}"
might also be used as shorthand for :0read!
or :0r!
that you have likely used in vi
mode (it is literally the same thing) but the :
is optional here and some implementations do not support "r"ead address of zero.
"r"eading directly to the special line #0 (or from line 1) would automatically push everything "down", and then you just :wq
to save your changes.
$ head -n 3 true.txt | nl -ba
1 +++ TOP +++
2 TRUE(1) User Commands TRUE(1)
3
Also, most classic sed
implementations do not have extensions (like \U&
) that ex
should have by default.
Upvotes: 0
Reputation: 504
The simplest solution I found is:
echo -n "<text to add>" | cat - myFile.txt | tee myFile.txt
Notes:
| tee myFile.txt
if you don't want to change the file contents.-n
parameter if you want to append a full line.&> /dev/null
to the end if you don't want to see the output (the generated file).# make it executable (use u+x to allow only current user)
chmod +x cropImage.ts
# append the shebang
echo '#''!'/usr/bin/env ts-node | cat - cropImage.ts | tee cropImage.ts &> /dev/null
# execute it
./cropImage.ts myImage.png
Upvotes: 3
Reputation: 4230
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.
Upvotes: 27
Reputation: 11580
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
Upvotes: 0
Reputation: 7708
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"
Upvotes: 0
Reputation: 75545
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.
Upvotes: 4
Reputation: 5072
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
Upvotes: 4
Reputation: 229
There is a very easy way:
echo "your header" > headerFile.txt
cat yourFile >> headerFile.txt
Upvotes: 7
Reputation: 161614
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,}
Upvotes: 518
Reputation: 91
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.
Upvotes: 9
Reputation: 29
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.
Upvotes: 2
Reputation: 193
You can use cat -
printf '%s' "some text at the beginning" | cat - filename
Upvotes: 16
Reputation: 1018
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
Upvotes: 89
Reputation: 881133
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.
Upvotes: 32