Ruby:插入一个字符串after/before一个模式

Ruby: Insert a string after/before a pattern

我知道如何在文件末尾和文件开头添加字符串(或文本),但无法google插入字符串(带变量)after/before一个模式。

例如,

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

现在,我想添加另一个名称服务器,如下所示。

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

我可以用 sed 轻松做到这一点,但只是想用 Ruby 寻找出路。

更新: 我已经写了下面的代码,但是这个替换了最后一行并没有添加一个。我想调整 file.seek 会对我有所帮助,但不确定如何。

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 

这是一个 Ruby "one-liner",我认为您正在尝试这样做。我创建了一个与您的第一个文件内容匹配的 resolv.conf 文件。然后下面的 Ruby "one-liner",为了便于阅读,我将其分成几行,搜索以 "nameserver" 开头的行,并插入一个包含您定义的 IP 的任意新 namservers 列表。

$ 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

如果你真的想把它作为一行,你必须在需要换行的地方添加分号:

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

-i.$SECONDS 标志告诉 Ruby 解释器就地修改您的输入文件,并使用 $SECONDS 的文件扩展名保存原始版本,这是seconds 你的终端会话一直存在。这使得你不太可能用错误的代码永久破坏一个好的文件。如果您需要,备份副本就在那里。你只需要事后清理即可。

编辑: 这是一个将行插入现有文件的简短脚本。请注意,这不会像单行文件那样保存输入文件的多个副本。此脚本读取输入文件 (resolv.conf),将修改后的输出保存到临时文件,然后重命名该临时文件,替换原始文件。你会在终端中 运行 这样 $ ./script.rb resolv.conf

脚本:

#! /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

有关 Tempfile class 的 Ruby 文档,了解 begin... ensure... end 用法的解释以及 Tempfile 对象上的显式 close

非常感谢 Jamin。我也稍微修改了您的代码以满足我未来的需要,就像有人想在 keyword/pattern 之前添加一段带空格的行一样。这就是我想出的。可能这对某人有帮助。

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