How to replace an entire line in a text file by line number
Solution 1
Not the greatest, but this should work:
sed -i 'Ns/.*/replacement-line/' file.txt
where N
should be replaced by your target line number. This replaces the line in the original file. To save the changed text in a different file, drop the -i
option:
sed 'Ns/.*/replacement-line/' file.txt > new_file.txt
Solution 2
I actually used this script to replace a line of code in the cron file on our company's UNIX servers awhile back. We executed it as normal shell script and had no problems:
#Create temporary file with new line in place
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
#Copy the new file over the original file
mv /dir/temp_file /dir/file
This doesn't go by line number, but you can easily switch to a line number based system by putting the line number before the s/
and placing a wildcard in place of the_original_line
.
Solution 3
Let's suppose you want to replace line 4 with the text "different". You can use AWK like so:
awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt
AWK considers the input to be "records" divided into "fields". By default, one line is one record. NR
is the number of records seen. $0
represents the current complete record (while $1
is the first field from the record and so on; by default the fields are words from the line).
So, if the current line number is 4, print the string "different" but otherwise print the line unchanged.
In AWK, program code enclosed in { }
runs once on each input record.
You need to quote the AWK program in single-quotes to keep the shell from trying to interpret things like the $0
.
EDIT: A shorter and more elegant AWK program from @chepner in the comments below:
awk 'NR==4 {$0="different"} { print }' input_file.txt
Only for record (i.e. line) number 4, replace the whole record with the string "different". Then for every input record, print the record.
Clearly my AWK skills are rusty! Thank you, @chepner.
EDIT: and see also an even shorter version from @Dennis Williamson:
awk 'NR==4 {$0="different"} 1' input_file.txt
How this works is explained in the comments: the 1
always evaluates true, so the associated code block always runs. But there is no associated code block, which means AWK does its default action of just printing the whole line. AWK is designed to allow terse programs like this.
Solution 4
Given this test file (test.txt)
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Duis eu diam non tortor laoreet
bibendum vitae et tellus.
the following command will replace the first line to "newline text"
$ sed '1 c\
> newline text' test.txt
Result:
newline text
consectetur adipiscing elit.
Duis eu diam non tortor laoreet
bibendum vitae et tellus.
more information can be found here
http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/
Solution 5
in bash, replace N,M by the line numbers and xxx yyy by what you want
i=1
while read line;do
if((i==N));then
echo 'xxx'
elif((i==M));then
echo 'yyy'
else
echo "$line"
fi
((i++))
done < orig-file > new-file
EDIT
In fact in this solution there are some problems, with characters "\0" "\t" and "\"
"\t", can be solve by putting IFS= before read: "\", at end of line with -r
IFS= read -r line
but for "\0", the variable is truncated, there is no a solution in pure bash : Assign string containing null-character (\0) to a variable in Bash But in normal text file there is no nul character \0
perl would be a better choice
perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file
Related videos on Youtube
user788171
Updated on July 08, 2022Comments
-
user788171 almost 2 years
I have a situation where I want a bash script to replace an entire line in a file. The line number is always the same, so that can be a hard-coded variable.
I'm not trying to replace some sub-string in that line, I just want to replace that line entirely with a new line.
Are there any bash methods for doing this (or something simple that can be thrown into a .sh script).
-
steveha almost 12 yearsI didn't even think of trying for a pure BASH solution!
-
chepner almost 12 yearsUseless use of cat:
sed -e "s/.../.../" /dir/file > /dir/temp_file
-
chepner almost 12 yearsA little shorter:
awk 'NR==4 {$0="different"} { print }' input_file.txt
. -
SourceSeeker almost 12 years@chepner: A little shorter:
awk 'NR==4 {$0="different"}1' input_file.txt
-
user788171 almost 12 yearsIs there a way to make sed modify the file in question instead of dumping to screen?
-
user788171 almost 12 yearsI am now hit with sed: illegal option -- i is there a fix for this?
-
steveha almost 12 years@DennisWilliamson, I don't even know how that works! What does that trailing
1
do? (Note: I tested it and it does indeed work! I just don't understand how.) -
chepner almost 12 yearsI figured there'd be a way to abbreviate the unconditional print! @stevaha: the 1 is just a true value, meaning a "pattern" that always matches. And the default action for a match is to print the current line.
-
Clayton Stanley almost 12 yearssudo port install sed? are you on a mac? if so, just use the *nix version
-
Clayton Stanley almost 12 yearsUseless for the interpreter/compiler maybe, but not for a human reading it. @Kyle's code reads nicely left to right; the idiom you used IMO does not, due to the fact that the verb is before the noun.
-
Danijel over 10 yearsFor me it says:
sed: -e expression #1, char 26: unknown option to ``s'
and my line is:sed -i '7s/.*/<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/</param-value>/' $TCE_SVN_HOME\trunk\tce\EWC\WebContent\WEB-INF\web.xml
. Any idea? -
chepner over 10 yearsEach
/
in the replacement text would be interpreted as the closing slash of thes
command unless escaped (\/
). The easiest thing to do, though, is to pick a different, unused character as the delimiter. For example,sed -i '7s{.*}{<param-value>http://...}' $TCE_SVN_HOME/trunk...
. -
adelphus about 9 yearsThis should be the correct answer. The c flag does exactly what is required (replaces a numbered line with given text).
-
func0der almost 9 yearsThat explanation is a little confusing and does not seem to work. If you guys have problems with sed and its delimiter setting capabilities you may want to have a look at this: grymoire.com/Unix/Sed.html#uh-2 It says the first character behind the
s
determines the delimiter. So to change your command to use for example the#
it would be like this:sed -i '7s#.*#<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/</param-value>#'
-
sikisis over 8 yearsbut it my bash why the result only shows
${newline}
? -
Leon S. over 7 yearsIf the
-i
command doesn't work on your machine, check the man-page. For me the command required a backup file extension after the flag, which you can leave empty:-i ''
, and in some other version of sed the syntax is--in-place=''
. -
ELLIOTTCABLE about 7 yearsTo expand on @meonlol's, macOS requires an
-e
if-i
is given, as well; thus, the correct command becomes:sed -e 'Ns/.*/replacement-line/' -i '' file.txt
-
Gabriel Devillers over 6 yearsAlternative syntax with sed that does not echo the file on stdout: stackoverflow.com/a/13438118/4669135
-
Rob over 6 yearswhy do you need a loop for this example, just obfuscates the solution?
line=5; sed -i "${line}s/.*/replaced by '$i'!/" output.dat
-
Pubudu Dodangoda over 6 yearsIs there a way to merge those two lines, for example by something like,
sed -e "s/.../.../" /dir/file > /dir/file
-
Victoria Stuart about 6 years
sed
streams the entire file, but as noted in this answer, specifying the line number (if known) helps: in my case, a ~2-fold increase in execution speed (GNU sed 4.5). You cangrep -n
orripgrep
(rg
) to find line numbers, based on pattern searches. -
gsamaras over 5 yearsUse double quotes if the replacement-line is not fixed, e.g. it's a variable, like this:
sed -i "Ns/.*/foo=$myVar" file.txt
. -
chepner over 5 years@gsamaras You have to be careful with
myVar
in that case, though. Its value needs to be properly escaped, e.g. ifmyVar=3/4
, you'll get an error fromsed
; the value would have to bemyVar='3\/4'
instead. -
stackunderflow about 5 yearsIt's the right answer, but why the ugly line break?
sed '1 cnewline text' test.txt
would do it as well. -
Chandu almost 4 yearsYour don't need a loop for this
-
SeanFromIT almost 4 years@PubuduDodangoda sed -i would accomplish that
-
li ki almost 3 yearsFor anyone who wants to know why
-i ''
: BSD sed: extra characters at the end of d command - Stack Overflow -
a.t. over 2 yearsThis was, for me, the easiest answer to convert into a function with a variable line number, variable new line, and a variable filepath. And for my use case, I did not need to escape any characters even though my new line contained
/
,-
,=
and;
. Thank you! Ps. after having posted this comment, I scrolled down Daniel Bigham's answer. -
Nahuel Fouilleul over 2 yearsThis answer is quite old. Now, I would use the perl command at the end, possibly passing the variables by environment.
-
Admin over 2 yearsAs it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
-
sapanoia over 2 yearsThe question is specifically about replacing a line with a given number.
grep
is not needed here. -
justin.m.chase over 2 yearsThis is the best answer by far, lol
-
Erwann over 2 yearsWhat about the last line? I guess
N=$(wc -l file | awk '{print $1;}'
, but cumbersome. -
chepner over 2 years
sed
uses$
as the address of the last line:$s/.../.../
.