简体   繁体   中英

Ruby: Insert a string after/before a pattern

I know how to add string(or text) to end of the file as well as beginning of the file, but could not google out the way to insert string (with a variable) after/before a pattern.

For example,

root@vikas:~# cat /etc/resolv.conf
search reachvikas.com
nameserver 192.168.1.27
root@vikas:~#

Now, I want to add another nameserver like below.

root@vikas:~# cat /etc/resolv.conf
search reachvikas.com
nameserver 192.168.181.2
nameserver 192.168.1.27
root@vikas:~#

I can do this with sed easily, but just looking a way out with Ruby.

Update : I have written below code, but this replaces the last line does not adds one. I guess tweaking file.seek would help me, but not sure how.

File.open('/etc/resolv.conf', 'r+') do |file|  
  count = Integer(0)  
  file.each do |line|  
  #puts count  
    if count == 1  
      #puts count.to_i  
      file.seek(-1, IO::SEEK_CUR)  
      file.puts("\nnameserver 192.168.181.2")  
     end  
   count += 1  
   end  
end 

Here's a Ruby "one-liner" that does what I think you're trying to do. I created a resolv.conf file matching your first file contents. Then the following Ruby "one-liner", which I broke into several lines for readability, searches for a line that begins with "nameserver" and inserts an arbitrary list of new namservers with IPs you define.

$ cat resolv.conf
search reachvikas.com
nameserver 192.168.1.27

$ ruby -wnl -i.$SECONDS -e '
BEGIN { server_ips = %w(
  ip1
  ip2
  ip3
  ) }
if $_.start_with?("nameserver")
  server_ips.each{ |ip| puts "nameserver #{ip}"; }
end
puts $_
' resolv.conf

$ ls resolv.conf*
resolv.conf       resolv.conf.27729

$ cat resolv.conf
search reachvikas.com
nameserver ip1
nameserver ip2
nameserver ip3
nameserver 192.168.1.27

$ cat resolv.conf.27729
search reachvikas.com
nameserver 192.168.1.27

If you truly want it as a one-liner, you have to add semicolons where line breaks are needed:

ruby -wnl -i.$SECONDS -e 'BEGIN { server_ips = %w(ip1 ip2 ip3); }; if $_.start_with?("nameserver") ; server_ips.each{|ip| puts "nameserver #{ip}";}; end; puts $_;' resolv.conf

The -i.$SECONDS flag tells the Ruby interpreter to modify your input file in-place and to save the original version with a filename extension of $SECONDS , which is the number of seconds your terminal session has been alive. That makes it very unlikely you will permanently clobber a good file with bad code. The backup copies are there if you need them. You just have to clean up afterwards.

EDIT: Here's a short script that inserts rows into an existing file. Note that this does not save multiple copies of the input file like the one-liner does. This script reads an input file (resolv.conf), saves modified output to a temp file, then renames that temp file, replacing the original file. You would run this in the terminal like this $ ./script.rb resolv.conf

Script:

#! /usr/bin/env ruby

require 'tempfile'
require 'fileutils'

server_ips = %w(
  ip1
  ip2
  ip3
)

input_file = ARGV[0]
temp_file = Tempfile.new("#{input_file}.temp")
modified = false

begin
  File.open(input_file, 'r') do |file|
    file.each_line do |line|
      if modified == false && line.start_with?('nameserver')
        server_ips.each do |ip|
          temp_file.puts "nameserver #{ip}"
        end
        modified = true
      end
      temp_file.print line
    end
  end
  temp_file.close
  FileUtils.mv(temp_file.path, input_file)
ensure
  temp_file.close!
end

See the Ruby documentation for the Tempfile class for an explanation of the begin... ensure... end usage and the explicit close on the Tempfile object.

Many thanks Jamin. I have slightly modified your code to suit my future needs as well, like if someone wants to add a block of lines with spaces before a keyword/pattern. This is what I have come up with. May be this helps someone.

txt_to_insert = %q(nameserver 192.168.181.2
nameserver 8.8.8.8)

input_file = "/etc/resolv.conf"
temp_file = Tempfile.new("tmp_file.temp")
modified = false

begin
  File.open(input_file, 'r') do |file|
    file.each_line do |line|
      if modified == false && line.start_with?('nameserver')
        temp_file.puts txt_to_insert
        modified = true
      end
     temp_file.print line
    end
  end
  temp_file.close
  FileUtils.mv(temp_file.path, input_file)
  ensure
    temp_file.close!
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM