所以,如果标题没有意义,这就是我要做的事情:
我有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
如您所见,它是ip地址,以“:”
分隔File2基本上是一个apache虚拟主机条目或httpd.conf文件。这并不重要。只要知道file2包含那里某处file1第一列的ip地址。它们需要被file1的第二列替换。
出于某种原因,这个简单的问题让我感到困惑。我已经尝试了一些非常粗糙的东西,但一直陷入困境。
我知道我可以使用awk将它们分开,我知道我可以将其传输到sed以对文件2进行操作。
但我似乎无法绕过将第1列“映射”到第2列的最佳方式,以便实际发生这种情况。
我愿意使用perl,ruby或python,或者真正实现这一目标的任何方法,我非常想简要解释一下如何解决这个问题。
请询问任何澄清,我很乐意提供。
提前非常感谢!
答案 0 :(得分:2)
将文件1中的IP对读入哈希值,例如: $ip{$old} = $new
。我假设没有重复的IP。通过file2查找IP,并使用正则表达式,如:
s#($IPregex)# $ip{$1} // $1 #eg;
代码类似:
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;
}
根据需要重定向到输出文件。可能需要更好的IP正则表达式。
答案 1 :(得分:1)
perl -ne '/(.*):(.*)/; (exists $ips{$1}) ? (print "$ips{$1}\n") : ($ips{$1} = $2);' f1 f2
这循环遍历文件f1然后文件f2。它将它们分成':'字符,如果我们之前没有看过前半部分,请将其粘贴在哈希中。如果我们之前看过前半部分,请打印我们存储在哈希中的值。
答案 2 :(得分:1)
sed -e "s:$(sed -e ':a;$!N;s/\n/:g;s:/g;ta' file1):" file2
内部sed
为外部sed创建一个多表达式正则表达式以应用于file2 ..
要安全地更新原始文件,您可以通过sponge
(来自包moreutils)将输出传输到ir。
答案 3 :(得分:1)
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
答案 4 :(得分:0)
Id使用perl。让我们称之为mapper.pl
。将地图文件作为arg,然后将stdin
映射到stdout
。所以你像这样使用它
perl mapper.pl file1 < file2 > file2.new
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
答案 5 :(得分:0)
感谢所有出色的答案!
我受到他们的启发,创造了一个红宝石版本:(它可以使用一些工作/减少,它不是非常rubyesque,但它的工作原理)
#!/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