How do I add a line of text to the middle of a file using bash?

LinuxBashSedAwkGrep

Linux Problem Overview


I'm trying to add a line of text to the middle of a text file in a bash script. Specifically I'm trying add a nameserver to my /etc/resolv.conf file. As it stands, resolv.conf looks like this:

# Generated by NetworkManager
domain dhcp.example.com
search dhcp.example.com
nameserver 10.0.0.1
nameserver 10.0.0.2
nameserver 10.0.0.3

My goal is to add nameserver 127.0.0.1 above all other nameserver lines, but below any text above that. In the end I want to my resolve.conf file to look like this:

# Generated by NetworkManager
domain dhcp.example.com
search dhcp.example.com
nameserver 127.0.0.1
nameserver 10.0.0.1
nameserver 10.0.0.2
nameserver 10.0.0.3

How is this possible via a bash script? Is this something sed or awk can do? Or would creative greping to recreate the file be my best move?

Linux Solutions


Solution 1 - Linux

Here is a solution using sed:

$ sed -n 'H;${x;s/^\n//;s/nameserver .*$/nameserver 127.0.0.1\n&/;p;}' resolv.conf

# Generated by NetworkManager
domain dhcp.example.com
search dhcp.example.com
nameserver 127.0.0.1
nameserver 10.0.0.1
nameserver 10.0.0.2
nameserver 10.0.0.3

How it works: first, suppress the output of sed with the -n flag. Then, for each line, we append the line to the hold space, separating them with newlines:

H

When we come to the end of the file (addressed by $) we move the content of the hold space to the pattern space:

x

If the first line in pattern space is blank we replace it with nothing.

s/^\n//

Then we replace the first line starting with nameserver by a line containing nameserver 127.0.0.1, a new line (Your version of sed may not support \n, in which case replace the n with a literal newline) and the original line (represented by &):

s/nameserver .*$/nameserver 127.0.0.1\n&/

Now we just need to print the results:

p

Solution 2 - Linux

Assuming you want to insert immediately after the search line, this is much simpler:

sed -ie '/^search/a nameserver 127.0.0.1' filename
  • -i : edit file in place
  • -e : allows the execution of a script/commands inside sed expression
  • a mynewtext : command that tells sed to insert the text mynewtext after matched pattern

Solution 3 - Linux

awk '/^nameserver/ && !modif { printf("INSERT\n"); modif=1 } {print}'

Solution 4 - Linux

How about something like:

sed -e ':a;N;$!ba;s/nameserver/nameserver 127.0.0.1\nnameserver/' /etc/resolv.conf

(similar to this: https://stackoverflow.com/questions/1577057/sed-find-pattern-over-two-lines-not-replace-after-that-pattern/1582743#1582743)

Solution 5 - Linux

Here's a Perl solution:

perl -lne 'if (not $f and /^nameserver/){ print "nameserver 127.0.0.1"; $f=1 }; print' resolv.conf

  • -n loop around every line of the input file, do not automatically print every line

  • -l removes newlines before processing, and adds them back in afterwards

  • -e execute the perl code

$f is used as a flag to indicate that the nameserver string has already been found

Solution 6 - Linux

This might work for you:

 sed -e '/nameserver/{x;/./b;x;h;i\nameserver 127.0.0.1' -e '}' resolv.conf

Or GNU sed:

sed -e '0,/nameserver/{//i\nameserver 127.0.0.1' -e '}' resolv.conf

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPHLAKView Question on Stackoverflow
Solution 1 - LinuxbrandizziView Answer on Stackoverflow
Solution 2 - LinuxJim GarrisonView Answer on Stackoverflow
Solution 3 - LinuxKaroly HorvathView Answer on Stackoverflow
Solution 4 - LinuxsagiView Answer on Stackoverflow
Solution 5 - LinuxChris KoknatView Answer on Stackoverflow
Solution 6 - LinuxpotongView Answer on Stackoverflow