Необходимо заменить строку в file2, которая соответствует первому столбцу file1 вторым столбцом file1 - PullRequest
2 голосов
/ 12 октября 2011

Итак, если название не имеет смысла, вот что я пытаюсь сделать:

У меня есть файл1:

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 содержит IP-адреса из первого столбца file1 где-то там. И их нужно заменить на второй столбец file1.

По какой-то причине эта простая проблема привела меня в замешательство. Я пробовал некоторые довольно грубые вещи, но продолжаю застрять.

Я знаю, что могу разделить их с помощью awk, и я знаю, что могу передать это в sed для обработки файла 2.

Но я, кажется, не могу обернуть голову вокруг наилучшего способа "сопоставить" столбец 1 с столбцом 2, чтобы это могло действительно произойти.

Я готов использовать perl, или ruby, или python, или любой другой метод для достижения этой цели, и мне очень хотелось бы краткое объяснение того, как вы можете решить эту проблему.

Пожалуйста, попросите разъяснений, и я буду рад их предоставить.

Заранее большое спасибо!

Ответы [ 6 ]

2 голосов
/ 12 октября 2011

Считать IP-пары из файла file1 в хеш, например, $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 голос
/ 12 октября 2011
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
1 голос
/ 12 октября 2011
sed -e "s:$(sed -e ':a;$!N;s/\n/:g;s:/g;ta' file1):" file2

Внутренний sed создает регулярное выражение с несколькими выражениями для внешнего sed для применения к file2 ..
Чтобы безопасно обновить исходный файл insitu, вы можете передать вывод через ir sponge (из пакета moreutils ).

1 голос
/ 12 октября 2011
perl  -ne '/(.*):(.*)/; (exists $ips{$1}) ? (print "$ips{$1}\n") : ($ips{$1} = $2);' f1 f2

Это зацикливает файл f1, затем файл f2.Он разделяет их на символ ':', и если мы не видели первую половину раньше, вставьте его в хеш.Если мы видели первую половину ранее, выведите значение, которое мы сохранили в хэше.

0 голосов
/ 13 октября 2011

Спасибо за все отличные ответы!

Они вдохновили меня на создание версии ruby: (она может использовать некоторую работу / сокращение, пока она не очень рубиновая, но работает)

#!/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
0 голосов
/ 12 октября 2011

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...