Sobrique
Sobrique

Reputation: 53508

Perl in place editing within a script (rather than one liner)

So, I'm used to the perl -i to use perl as I would sed and in place edit.

The docs for $^I in perlvar:

$^I The current value of the inplace-edit extension. Use undef to disable inplace editing.

OK. So this implies that I can perhaps mess around with 'in place' editing in a script?

The thing I'm having trouble with is this:

If I run:

perl -pi -e 's/^/fish/' test_file

And then deparse it:

BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
    s/^/fish/;
}
continue {
    die "-p destination: $!\n" unless print $_;
}

Now - if I were to want to use $^I within a script, say to:

 foreach my $file  ( glob "*.csv" ) {
     #inplace edit these files - maybe using Text::CSV to manipulate? 
 }

How do I 'enable' this to happen? Is it a question of changing $_ (as s/something/somethingelse/ does by default) and letting perl implicitly print it? Or is there something else going on?

My major question is - can I do an 'in place edit' that applies a CSV transform (or XML tweak, or similar).

I appreciate I can open separate file handles, read/print etc. I was wondering if there was another way. (even if it is only situationally useful).

Upvotes: 13

Views: 11537

Answers (2)

There is a much simpler answer, if your script is always going to do in-place editing and your OS uses "shebang" (runs scripts that start with '#!'):

#!perl -i
while (<>) {
    print "LINE: $_"
}

Will add 'LINE: ' at the beginning of a line for each file it's given. (Note that you'd probably use the full path to perl, i.e., "#!/usr/bin/perl -i")

You can also call your script as:

% perl -i <script> <file1> <file2> ...

To run script as an in-place editor on file1, file2, etc.., if you don't have shebang support.

Upvotes: 4

Borodin
Borodin

Reputation: 126762

The edit-in-place behaviour that is enabled by the -i command-line option or by setting $^I works only on the ARGV file handle. That means the files must either be named on the command line or @ARGV must be set up within the program

This program will change all lower-case letters to upper-case in all CSV files. Note that I have set $^I to a non-null string, which is advisable while you are testing so that your original data files are retained

use strict;
use warnings;

our $^I = '.bak';

while ( my $file = glob '*.csv' ) {

  print "Processing $file\n";

  our @ARGV = ($file);

  while ( <ARGV> ) {
     tr/a-z/A-Z/;
     print;
  }
}

Upvotes: 14

Related Questions