我正在寻找一个脚本来搜索模式的文件(或文件列表),如果找到,则用给定的值替换该模式。
思想?
答案 0 :(得分:181)
这是一个快速的简短方法。
file_names = ['foo.txt', 'bar.txt']
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/search_regexp/, "replacement string")
# To merely print the contents of the file, use:
puts new_contents
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts new_contents }
end
答案 1 :(得分:97)
实际上,Ruby确实具有就地编辑功能。像Perl一样,你可以说
ruby -pi.bak -e "gsub(/oldtext/, 'newtext')" *.txt
这会将双引号中的代码应用于当前目录中名称以“.txt”结尾的所有文件。编辑文件的备份副本将以“.bak”扩展名创建(我认为“foobar.txt.bak”)。
注意:这似乎不适用于多行搜索。对于那些,你必须用另一个不那么漂亮的方式来做,在正则表达式周围有一个包装脚本。
答案 2 :(得分:40)
答案 3 :(得分:11)
实际上没有一种方法可以就地编辑文件。当你可以逃脱它时通常做的事情(即文件不是太大)是,你将文件读入内存(File.read
),对读取字符串执行替换(String#gsub
)然后将更改后的字符串写回文件(File.open
,File#write
)。
如果文件大到不可行,你需要做的就是以块的形式读取文件(如果要替换的模式不会跨越多行,那么一个块通常意味着一行 - 你可以使用File.foreach
逐行读取文件,并为每个块执行替换并将其附加到临时文件。完成对源文件的迭代后,关闭它并使用FileUtils.mv
用临时文件覆盖它。
答案 4 :(得分:8)
另一种方法是在Ruby中使用inplace编辑(而不是从命令行):
#!/usr/bin/ruby
def inplace_edit(file, bak, &block)
old_stdout = $stdout
argf = ARGF.clone
argf.argv.replace [file]
argf.inplace_mode = bak
argf.each_line do |line|
yield line
end
argf.close
$stdout = old_stdout
end
inplace_edit 'test.txt', '.bak' do |line|
line = line.gsub(/search1/,"replace1")
line = line.gsub(/search2/,"replace2")
print line unless line.match(/something/)
end
如果您不想创建备份,请将“.bak”更改为“”。
答案 5 :(得分:6)
这对我有用:
filename = "foo"
text = File.read(filename)
content = text.gsub(/search_regexp/, "replacestring")
File.open(filename, "w") { |file| file << content }
答案 6 :(得分:6)
这是在给定目录的所有文件中查找/替换的解决方案。基本上我接受了sepp2k提供的答案并扩展了它。
# First set the files to search/replace in
files = Dir.glob("/PATH/*")
# Then set the variables for find/replace
@original_string_or_regex = /REGEX/
@replacement_string = "STRING"
files.each do |file_name|
text = File.read(file_name)
replace = text.gsub!(@original_string_or_regex, @replacement_string)
File.open(file_name, "w") { |file| file.puts replace }
end
答案 7 :(得分:4)
require 'trollop'
opts = Trollop::options do
opt :output, "Output file", :type => String
opt :input, "Input file", :type => String
opt :ss, "String to search", :type => String
opt :rs, "String to replace", :type => String
end
text = File.read(opts.input)
text.gsub!(opts.ss, opts.rs)
File.open(opts.output, 'w') { |f| f.write(text) }
答案 8 :(得分:1)
如果您需要跨行边界进行替换,那么使用ruby -pi -e
将无法正常工作,因为p
一次处理一行。相反,我推荐以下内容,尽管它可能会因多GB文件而失败:
ruby -e "file='translation.ja.yml'; IO.write(file, (IO.read(file).gsub(/\s+'$/, %q('))))"
正在寻找引号后面的空格(可能包括新行),在这种情况下,它会删除空格。 %q(')
只是引用引号字符的一种奇特方式。
答案 9 :(得分:0)
这里是jim的一个衬里的替代品,这次是在剧本中
async
将其保存在脚本中,例如replace.rb
使用
从命令行开始ARGV[0..-3].each{|f| File.write(f, File.read(f).gsub(ARGV[-2],ARGV[-1]))}
* .txt可以替换为其他选择或某些文件名或路径
细分,以便我可以解释发生了什么,但仍然可执行
replace.rb *.txt <string_to_replace> <replacement>
答案 10 :(得分:0)
我正在使用 tty-file gem
除了替换之外,它还包括追加、前置(在文件内的给定文本/正则表达式上)、差异等。