This is what backreferences are for. Just surround the section of text you want to capture with parentheses. The first set of parentheses are available in $1, the second in $2, and so on.
s/(\s[0-9]\s[0-9]{3})/$1I/
With Perl 5.10 we gained named captures, so you can say
s/(?<bodytext>\s[0-9]\s[0-9]{3})/$+{bodytext}I/
The stuff inbetween <
and >
is the name. Names become keys in the %+
variable and the values are the captured text.
Another solution is to use a zero-width positive look-behinds
s/(?<=\s[0-9]\s[0-9]{3})/I/
or its, new to Perl 5.10, shorthand \K
s/\s[0-9]\s[0-9]{3}\K/I/
Try
perl -pi -e 's/(\s[0-9]\s[0-9][0-9][0-9])/$1I/' filename
If you use double quotes the $1 is interpolated by the shell before Perl ever sees it. If you have problems with something you think should work, it may be a good idea to take a look at what Perl is seeing. You can do this with B::Deparse:
perl -MO=Deparse -pi -e "s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/" filename
That will produce the following output.
BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
s/(\s[0-9]\s[0-9][0-9][0-9])/I/;
}
continue {
print $_;
}
-e syntax OK
From this we can see that $1
is missing. Lets try again with single quotes:
perl -MO=Deparse -pi -e 's/(\s[0-9]\s[0-9][0-9][0-9])/$1I/' filename
BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/;
}
continue {
print $_;
}
-e syntax OK
And once with escaping:
perl -MO=Deparse -pi -e "s/(\s[0-9]\s[0-9][0-9][0-9])/\$1I/" filename
BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/;
}
continue {
print $_;
}
-e syntax OK