[英]Need to replace string in file2 that matches first column of file1 with second column of file1
So, if the title didn't make sense, here's what I'm trying to do: 因此,如果标题没有意义,这就是我想要做的:
I have file1: 我有file1:
66.115.135.84:123.123.123.1
66.115.135.85:123.123.123.2
66.115.135.86:123.123.123.3
66.115.135.87:123.123.123.4
66.115.135.88:123.123.123.5
66.115.135.89:123.123.123.6
66.115.135.90:123.123.123.7
66.115.135.91:123.123.123.8
66.115.135.92:123.123.123.9
66.115.135.93:123.123.123.10
66.115.135.94:123.123.123.11
66.115.135.95:123.123.123.12
66.115.135.96:123.123.123.13
66.115.135.97:123.123.123.14
As you can see, it's ip addresses, separated by a ":" 如您所见,它是IP地址,以“:”分隔
File2 is basically an apache virtual host entry, or httpd.conf file. File2本质上是一个Apache虚拟主机条目或httpd.conf文件。 It doesn't really matter. 没关系。 Just know that file2 contains the ip addresses from the first column of file1 somewhere in there. 只是知道file2包含来自file1第一列的IP地址。 And they need to be replaced by the second column of file1. 并且它们需要替换为file1的第二列。
For some reason, this simple problem has left me bewildered. 由于某种原因,这个简单的问题使我感到困惑。 I've tried some pretty gnarly things, but keep getting stuck. 我已经尝试了一些非常粗糙的东西,但是一直卡住了。
I know I can separate them using awk, and i know i could pipe that into sed to act on file2. 我知道我可以使用awk分隔它们,并且我知道可以将其传送到sed中以对file2起作用。
But I can't seem to wrap my head around the best way to "map" column 1 to column 2 so that this can actually happen. 但是我似乎无法将最好的方法“将”第1列“映射”到第2列,以至于这种情况确实发生。
I'm willing to use perl, or ruby, or python, or really any method of achieving this, and I would very much like a brief explanation of how you are able to solve this. 我愿意使用perl或ruby或python或任何实现此目的的方法,并且我非常希望对如何解决此问题进行简要说明。
Please ask for any clarification, and I'll be glad to supply it. 请要求任何澄清,我们很乐意提供。
Thanks so much in advance! 非常感谢!
Read the IP pairs from file1 into a hash, eg $ip{$old} = $new
. 将IP1对从file1读入哈希,例如$ip{$old} = $new
。 I assume there are no duplicate IPs. 我假设没有重复的IP。 Go through file2 looking for IPs, and use a regex such as: 遍历file2寻找IP,并使用正则表达式,例如:
s#($IPregex)# $ip{$1} // $1 #eg;
Code something like: 代码类似:
use autodie;
open my $fh, '<', "file1";
my %ip;
while (<$fh>) {
chomp;
my ($key, $val) = split /:/, $_, 2;
$ip{$key} = $val;
}
open $fh, '<', "file2";
my $rx = qr/\b\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}\b/;
while (<$fh>) {
s#($rx)# $ip{$1} // $1 #eg;
print;
}
Redirect to output file as needed. 根据需要重定向到输出文件。 Might need a better regex for the IP. 可能需要更好的IP正则表达式。
perl -ne '/(.*):(.*)/; (exists $ips{$1}) ? (print "$ips{$1}\n") : ($ips{$1} = $2);' f1 f2
This loops over file f1 then file f2. 这将依次遍历文件f1和文件f2。 It splits them on the ':' character and if we haven't seen the first half before, stick it in the hash. 它将它们分割为':'字符,如果之前没有看到前一半,则将其粘贴在哈希中。 If we have seen the first half before, print the value we stored in the hash. 如果我们已经看过前半部分,请打印存储在哈希中的值。
sed -e "s:$(sed -e ':a;$!N;s/\n/:g;s:/g;ta' file1):" file2
The inner sed
creates a multi-expression regex for the outer sed to apply to file2.. 内部sed
为外部sed
创建一个多表达式正则表达式,以应用于file2。
To securely update your original file insitu, you can pipe the output to ir via sponge
(from package moreutils ). 为了安全地就地更新原始文件,您可以通过sponge
将输出通过管道传输到ir(来自moreutils包)。
awk '
FILENAME == ARGV[1] {
split($0, ary, /:/)
map[ary[0]] = ary[1]
next
}
{
for (i=1; i<=NF; i++) {
if ($i in map)
$i = map[$i]
}
print
}
' file1 file2 > file2.new
Id use perl. id使用perl。 Lets call it mapper.pl
. 让我们称之为mapper.pl
。 Takes map file as an arg, and then maps stdin
to stdout
. 将映射文件作为arg,然后将stdin
映射到stdout
。 So you use it like this 所以你这样用
perl mapper.pl file1 < file2 > file2.new
The mapper.pl
program is something like: mapper.pl
程序类似于:
use strict;
use warnings;
# Prototypes
sub readMap($);
# Main program
{
if( scalar(@ARGV) != 1 )
{
die "usage: mapper.pl mapfile";
}
my %map = readMap( $ARGV[0] );
while( my $line = <STDIN> )
{
foreach my $old ( keys(%map) )
{
my $old_re = $old;
# Escape metacharacters
$old_re =~ s/\W/\\$&/g;
$line =~ s/$old_re/$map{$old}/g;
}
print $line;
}
} # END main
sub readMap($)
{
my $mapname = $_[0];
my %map;
open( MAPFILE, "<$mapname" ) || die "open($mapname): $!";
while( my $line = <MAPFILE> )
{
if( $line =~ /^\s*([^:]+):(.*?)\s*$/ )
{
$map{$1} = $2;
}
else
{
warn "Invalid line: $line";
}
}
close( MAPFILE );
return( %map );
} # END readMap
Thanks for all of the great answers! 感谢您提供的所有出色答案!
I was inspired by them to create a ruby version: (it could use some work/reduction, it's not very rubyesque yet, but it works) 我受到他们的启发,创建了一个红宝石版本:(它可以进行一些工作/还原,虽然还不是很红宝石,但是可以用)
#!/usr/bin/ruby
#replaces old ips for new ips in virt file
@orig_ips=Array.new
@new_ips=Array.new
File.open("/home/kevin/scripts/ruby_scripts/test.virt", "r").each do |line|
if line =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
@orig_ips.push(line.split.last.chop)
end
end
File.open("/home/kevin/scripts/ruby_scripts/new_ip_list", "r").each do |line|
@new_ips.push(line.split.last)
end
f = File.open("/home/kevin/scripts/ruby_scripts/test.virt")
working_file = f.read
for count in 0..@orig_ips.count - 1 do
old = @orig_ips[count]
new = @new_ips[count]
working_file.gsub!(old, new)
end
puts working_file
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.