Michael said:
What I really have a problem with is this works:
perl -pi -e '@_=split; s/$_[2]/85/ ' file
In order to make it clearer as to what is going on, let's re-write
the code to the following equivalent code:
@fields = split(' ', $_);
$_ =~ s/$fields[2]/85/;
What this code is doing is splitting up the line into the @fields
array, and then searching for the $fields[2] string in $_ (the current
line) and replacing it, if found, with 85.
Notice that, if $fields[2] is a substring that happens to be found
inside one of the current line's previous elements, then that previous
element will be modified instead. For example, if you run that code on
the input:
high low hi hello
you will get the following line of output:
85gh low hi hello
That's because the first instance of "hi" (the third element) is
actually found as a substring of the first element.
If you want to make sure to change ONLY the third element, you might
want to try this line:
perl -wpi -e 's/^(\s*(\S+\s+){2})\S+/${1}85/' file
This specifically looks for two instances of non-whitespace followed by
whitespace (which is then followed by whitespace), and then substitues
what it finds with the first part of the line with your new value.
While this does not work:
perl -pi -e '@_=split; $_[2] = 85 ' file
Here's equivalent code:
@fields = split;
$fields[2] = 85;
Notice that, in this case, nothing is modifying the $_ variable. It's
being used to derive the @fields array (which then gets its third
element set to 85), but nothing actually modifies $_.
What I really want to do, is this:
perl -pi -e '@_=split; $_[2] = "85" ' file
That'll do pretty much the same thing as the previous piece of code
(for the same reasons).
In some instances, I want to put $_[-1] onto $_[2], and erase $_[-1].
But that's not working either.
Well, you can either split apart the fields into an array, modify
the array, and then re-join the array's fields into $_, like this:
perl -lpi -e '@F=split; $F[2]=$F[-1]; pop(@F); $_=join(" ",@F)' file
(The "-l" switch is used so that you don't have to explicitly print out
a newline.)
Incidentally, this code can be easily re-written to use perl's '-a'
switch, with autosplits the current line into the @F array:
perl -lapi -e '$F[2]=$F[-1]; pop(@F); $_=join(" ",@F)' file
Note, however, that this code will separate your fields out with a
single space no matter what whitespace they were separated with before.
If you want to keep the spacing as before, you might want to try
capturing & removing the last element, then substituting the third
element with what you captured:
perl -lpe 's/(\S+)\s*$// and $field=$1,
s/((\S+\s+){2})\S+/$1$field/'
It's not pretty, but it works.
I hope this helps, Michael.
-- Jean-Luc Romano