54

I am writing a script that will require me to add lines in a specific part of a config file. For example

Before:

ServerActors=IpServer.UdpServerUplink MasterServerAddress=unreal.epicgames.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master0.gamespy.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900
ServerActors=UWeb.WebServer

After:

ServerActors=IpServer.UdpServerUplink MasterServerAddress=unreal.epicgames.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master0.gamespy.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.qtracker.com MasterServerPort=27900
ServerActors=UWeb.WebServer

As you can see there is a new line added. How can my bash script insert the line? I'm guessing I will need to use sed.

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
dgibbs
  • 702
  • 2
  • 6
  • 10
  • There are multiple ways and languages to do so, probably `awk` and `sed` being the best ones. Should you indicate the logic in these lines addition, so we can help solving it. – fedorqui Aug 16 '13 at 11:34
  • It's hard to infer a rule from one complicated case. Do you want to insert `ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.qtracker.com MasterServerPort=27900` above every mention of `WebServer`? Or follow every `mplayer` line with a corresponding `qtracker` line, or what? – Beta Aug 16 '13 at 11:36
  • I think I found an answer. Not sure if there is a better way. But I have simply put in sed replace mplayer line with mplayer line *newline* qtracker line `sed -i 's/ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900/ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900\nServerActors=IpServer.UdpServerUplink MasterServerAddress=master.qtracker.com MasterServerPort=27900/g' /tmp/test` Its a little long but it seems to work. – dgibbs Aug 16 '13 at 11:54
  • or to simplyfy `sed -i 's/line3/line3\nline5/g' /tmp/test` – dgibbs Aug 16 '13 at 12:02
  • @dgibbs,that's usually how I do - replace string before/after I want to insert keeping original in there and adding the new thing. – akostadinov Aug 16 '13 at 14:36
  • possible duplicate of [How do I add a line of text to the middle of a file using bash?](http://stackoverflow.com/questions/6739258/how-do-i-add-a-line-of-text-to-the-middle-of-a-file-using-bash) – Big McLargeHuge May 25 '15 at 13:55

5 Answers5

115

If you want to add a line after a specific string match:

$ awk '/master.mplayer.com/ { print; print "new line"; next }1' foo.input
ServerActors=IpServer.UdpServerUplink MasterServerAddress=unreal.epicgames.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master0.gamespy.com MasterServerPort=27900
ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900
new line
ServerActors=UWeb.WebServer
Adrian Frühwirth
  • 42,970
  • 10
  • 60
  • 71
  • 4
    I wonder why this didn't get more up votes, it's a way more dynamic way of handling the solution than explicitly knowing the line number your search text is on. +1 from me – sadmicrowave Apr 15 '14 at 18:04
  • 1
    This is a better answer than the accepted one because it will reliably persist even if something else interacts with the file in question. e.g. I was using this on a Docker build of an nginx container and if someone were to add some config to it elsewhere, the accepted answer would break the build. This will not. – samtresler Feb 25 '15 at 21:19
  • 4
    Why doesn't piping this back into the same file work? `awk ... foo.input > foo.input` just empties that file – Andy Ray Jul 01 '16 at 22:43
  • 3
    @AndyRay Because shell redirection happens before any commands are run, which means the file is truncated immediately. See also [this answer](http://askubuntu.com/a/8418). The only way around this is using a temporary file, which for example `sed -i` does transparently. There's also `sponge` from `moreutils` which solves this problem. – Adrian Frühwirth Jul 02 '16 at 22:32
  • 3
    It shows the expected output, but how to add that output to the file? File is unchanged – Syed Asad Ali Jun 11 '18 at 10:57
  • @SyedAsadAli See my comment above your question. – Adrian Frühwirth Jun 12 '18 at 09:38
  • Is it possible to match a regular expression? I try to do it with [:space:] but it seems to not work. EDIT Ok it works – Couim Apr 29 '19 at 12:59
  • 1
    What's up with that `1` after `}` in `awk '/master.mplayer.com/ { print; print "new line"; next }1' foo.input`? EDIT: from @pieman72 's comment: If anyone else is confused, the 7 in this example can be any value that evaluates true. This is so that Awk knows to print every line. If there were no value there, then only the matched line (#5 in this case) would generate output ("new line text" in this case). – xdevs23 Apr 18 '20 at 17:12
36

You can use something like this:

Note that the command must be entered over multiple lines because sed does not allow coding a newline with "\n" or the Ctrl-V/Ctrl-M key combination like some tools. The backslash says "Ignore my hitting the return key, I'm not done with my command yet".

sed -i.bak '4i\
This is the new line\
' filename

This should do the trick (It will insert it between line 3 and 4).

If you want to put this command itself into a shell script, you have to escape the backslashes so they don't get eaten by bash and fail to get passed to sed. Inside a script, the command becomes:

sed -i.bak '4i\\
This is the new line\\
' filename
JaviMerino
  • 619
  • 10
  • 18
MPrazz
  • 569
  • 4
  • 3
18
awk 'NR==5{print "new line text"}7' file
Kent
  • 189,393
  • 32
  • 233
  • 301
  • 7
    sorry, for what is `7` here? ( `..."}7` ) – setevoy Jan 23 '14 at 11:14
  • 2
    @setevoy it will apply the default action of awk: print. – Kent Apr 16 '14 at 07:59
  • @Kent Must be a [bond](http://en.wikipedia.org/wiki/James_Bond) lover. But like you said bond should use `007` if he using `awk` so `+1`. `;)`! – jaypal singh Apr 16 '14 at 16:54
  • 9
    If anyone else is confused, the `7` in this example can be any value that evaluates true. This is so that Awk knows to print every line. If there were no value there, then only the matched line (#5 in this case) would generate output ("new line text" in this case). – pieman72 Apr 29 '14 at 07:50
5

You can add it with sed in your file filename after a certain string pattern match with:

sed '/pattern/a some text here' filename

in your example

sed '/master.mplayer.com/a \  new line' filename

(The backslash masks the first space in the new line, so you can add more spaces at the start)

source: https://unix.stackexchange.com/a/121166/20661

Community
  • 1
  • 1
rubo77
  • 19,527
  • 31
  • 134
  • 226
  • 1
    If you want alter file inserting the new line, you can add "-i" parameter to sed command. This will change file with" new line". sed -i '/master.mplayer.com/a \ new line' filename – McQuade Jul 05 '23 at 10:47
0

if you are using sed you need to use -i option to save content in original file otherwise it will only print output in terminal

sed -i '/pattern/a \some text here' filename