Reputation: 525
I wanted to grep a string at the first occurrence ONLY from a file (file.dat) and replace it by reading from another file (output). I have a file called "output" as an example contains "AAA T 0001"
#!/bin/bash
procdir=`pwd`
cat output | while read lin1 lin2 lin3
do
srt2=$(echo $lin1 $lin2 $lin3 | awk '{print $1,$2,$3}')
grep -m 1 $lin1 $procdir/file.dat | xargs -r0 perl -pi -e 's/$lin1/$srt2/g'
done
Basically what I wanted is:
When ever a string "AAA" is grep'ed from the file "file.dat" at the first instance, I want to replace the second and third column next to "AAA" by "T 0001" but still keep the first column "AAA" as it is. Th above script seems not to work.
Basically "$lin1" and $srt2 variables are not understood inside 's/$lin1/$srt2/g'
Example:
in my file.dat I have a row
AAA D ---- CITY COUNTRY
What I want is :
AAA T 0001 CITY COUNTRY
Any comments are very appreciated.
Upvotes: 0
Views: 1436
Reputation: 386676
perl -i -e'
{
my $f = shift(@ARGV);
open(my $fh, "<", $f)
or die("Can'\''t open $f: $!\n");
while (<$fh>) {
my ($s,$r) = /^(\S+)\s++(.*)$/;
$repl{$s} = $r;
}
}
while (<>) {
s{^(\S+)\s+\K(\S+\s*\S+)}{ delete($repl{$1}) // $2 }e;
print;
}
' output file.dat
Upvotes: 0
Reputation: 139701
Perl shines at this sort of task.
The code below reads the replacements from output
and remembers the new fields that go with the first occurrence of each key. Using Perl’s in-place editing, the program then reads the input line by line. When necessary, the code replaces fields 2 and 3 and also deletes the key from %replace
so as to only replace the first instance.
#! /usr/bin/env perl
use strict;
use warnings;
die "Usage: $0 replacements data-file\n" unless @ARGV == 2;
sub read_replacements {
my($path) = @_;
my %replace;
open my $fh, "<", $path or die "$0: open $path: $!";
while (<$fh>) {
chomp;
my($key,$f2,$f3) = split;
warn "$0: $path:$.: multiple replacements for key '$key'" if $replace{$key};
$replace{$key} = [$f2,$f3];
}
%replace;
}
my %replace = read_replacements shift @ARGV;
$^I = "~"; # in-place editing backup extension
while (<>) {
chomp;
my($key,@rest) = split;
if ($replace{$key}) {
splice @rest, 0, 2 => @{$replace{$key}};
$_ = join(" ", $key, @rest) . $/;
delete $replace{$key};
}
print;
}
Sample run:
$ cat output AAA T 0001 $ cat file.dat AAA D ---- CITY COUNTRY $ ./replace-first output file.dat $ cat file.dat AAA T 0001 CITY COUNTRY $ cat file.dat~ AAA D ---- CITY COUNTRY
In-place editing is a nice feature, and you could readily extend the above program to replace fields in an arbitrary number of files.
Upvotes: 1