Reputation: 37146
The following Perl one-liner works as I expect it to; it strips my file of leading and trailing backspaces and replaces intermediate whitespaces with a single tab:
$ perl -pi -le 's/^\s+//; s/\s+$//; s#\s+#\t#g;' file
What perplexes me is why I cannot get this to work via a system
call from within my Perl code:
system "perl -pi -le 's/^\s+//; s/\s+\$//; s#\s+#\t#g;' file"; # '$' backslashed
What's the issue here?
Upvotes: 1
Views: 1785
Reputation: 6524
There's no need to launch another process for -i, but in general you should localize some of the global variables:
sub do_stuff {
my $file = shift;
local ($_, $., $ARGV, *ARGV);
local ( $^I, @ARGV ) = ( '.bak', $file );
while ( <> ) {
s/..../..../;
print;
}
}
Upvotes: 3
Reputation: 3744
This is just the situation that Larry gave us alternate quote characters for. We would like to use single quotes for system()s arg so that we don't have to figure out what needs backslashing, but we also need single quotes in the quoted string itself. So, alternate quote characters to the rescue!
system q(perl -p -le 's/^\s+//; s/\s+$//; s#\s+#\t#g;' file);
Now you can copy/paste what works at the command line directly into your Perl source.
Upvotes: 0
Reputation: 6784
for Linux try
system q(perl -pi -le 's/^\s+//; s/\s+$//; s#\s+#\t#g;' file); # comments here
for M$ windows:
system q(perl -pi -le "s/^\s+//; s/\s+$//; s#\s+#\t#g;" file); # comments here
Upvotes: 0
Reputation: 164769
runrig showed how you don't have to make a subprocess just to use -i. Using -i internally is a bit weird, so there's two cleaner alternatives. The first is to use Tie::File which is fairly straightforward.
The other is to write to a temp file using File::Temp which is essentially what -i does.
my $tmp = File::Temp->new;
open my $fh, "<", $file or die "Can't open $file: $!";
while(<$fh>) {
s/.../.../;
print $tmp $_;
}
my $tmpfile = $tmp->filename;
rename $tmpfile, $file or die "Can't rename $tmpfile to $file: $!";
Upvotes: 1
Reputation: 29854
Inside double quotes '
has no functional value. Your string will be edited by Perl. My tests show that you are losing the \s
expressions. It's also interpolating the '\t'
. tab--although that might not be so much the problem.
Here's Data::Dumper
's take:
$s = 'perl -pi -le \'s/^s+//; s/s+$//; s#s+# #g;\' file';
Upvotes: 0
Reputation: 385657
say "perl -pi -le 's/^\s+//; s/\s+\$//; s#\s+#\t#g;' file";
produces
Unrecognized escape \s passed through at -e line 1.
Unrecognized escape \s passed through at -e line 1.
Unrecognized escape \s passed through at -e line 1.
perl -pi -le 's/^s+//; s/s+$//; s#s+# #g;' file
You want
system("perl -pi -le 's/^\\s+//; s/\\s+\$//; s#\\s+#\\t#g;' file");
Actually, why invoke the shell at all?
system('perl', '-i', '-ple' 's/^\\s+//; s/\\s+$//; s#\\s+#\\t#g;', 'file');
Upvotes: 2
Reputation: 76898
The double-quotes are interpreting everything.
try:
system "perl -pi -le 's/^\\s+//; s/\\s+\$//; s\#\\s+\#\\t\#g;' file";
Upvotes: 0
Reputation: 62099
You're forgetting that the backslashes get parsed first as a Perl double-quoted string, and then as a shell command.
The equivalent of the command line:
perl -pi -le 's/^\s+//; s/\s+$//; s#\s+#\t#g;' file
in a Perl script is
system "perl -pi -le 's/^\\s+//; s/\\s+\$//; s#\\s+#\\t#g;' file"
Although it's silly to launch another copy of Perl just for this. You're probably better off using a few more lines of code and doing it in the same process.
Upvotes: 1