How to replace an entire line in a text file by line number
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).
11 Answers 11
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
For me it says: sed: -e expression #1, char 26: unknown option to «s’ and my line is: sed -i ‘7s/.*/
Each / in the replacement text would be interpreted as the closing slash of the s command unless escaped ( \/ ). The easiest thing to do, though, is to pick a different, unused character as the delimiter. For example, sed -i ‘7s<.*>http://. >’ $TCE_SVN_HOME/trunk. .
That 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#.*#
To 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
Use double quotes if the replacement-line is not fixed, e.g. it’s a variable, like this: sed -i «Ns/.*/foo=$myVar» file.txt .
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 .
Useless 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.
Is there a way to merge those two lines, for example by something like, sed -e «s/. /. /» /dir/file > /dir/file
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:
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:
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.