Shakiba Moshiri
Shakiba Moshiri

Reputation: 23774

command-line-argument deduction as a special variable

My simple script in Perl

#!/usr/bin/perl                                            
use v5.20.1;                                               
use strict;                                                
use warnings;                                              

$| = 1;                                                    

my $string     = $ARGV[ 0 ];                               
my $match      = $ARGV[ 1 ];                               
my $substitute = $ARGV[ 2 ];                               

$string =~ m/match/g; # just for capturing the pattern                                     

$string =~ s/$match/only $substitute/g;                    

say "\$1[itself]  == $1";                                  
say "\$substitute == $substitute";                         
say "\$string     == $string";                             
say "prefix      == $`";                                   
say "match       == $&";                                   
say "suffix      == $'"; 

Input and Output:

$ perl temp 'I have 9 dollars' '(\d+)' '$1'
$1[itself]  == 9
$substitute == $1
$string     == I have only $1 dollars
prefix      == I have 
match       == 9
suffix      == dollars  

A thing that I am trying to do is a simple substitution by initializing the match and substitution variable from @ARGV. After that a simple match for initializing the special character such as $1. But when I want to pass the special character $1 from command-line to the script, it is deducted as a regular string and not the special variable $1 that I need for substitution

If I change the code from:

$string =~ s/$match/only $substitute/g;

to:

$string =~ s/$match/only $1/g;  

now it works!
1. Why $1 of the command line is different from $1 in the script?
2. Is there any way to solve it?

A screenshot of my console:

enter image description here


Edit

As ikegami suggested I installed and used the String::Substitution and could by using gsub_copy($line, $match, $substitute); deduced the substitution.
But still I need to use this substitution itself for printing it on the screen and colorize it for illustration that what happens.
In fact this purpose, is part of a rename script that read all file and by call rename function, changes the name of the files.

As you can see on the screenshot:

enter image description here

instead of for_$1 it should be for_Level on the screen. So does this module can return what it has deduced?
I am not talking about the sub match of the match group parentheses!
Also the author of the module has said:

This module does not save or interpolate $& to avoid the "considerable performance penalty"

May this screenshot clarify the subject:

enter image description here

Upvotes: 0

Views: 102

Answers (2)

ikegami
ikegami

Reputation: 385590

Why $1 of the command line is different from $1 in the script?

You're actually asking why

s/.../...$substitute.../

in your script is different than

s/.../...$1.../

in your script. For the same reason that

print($substitute);

is different than

print($1);

and that is that the value of $1 (the captured text) is different than the value of $substitute ($1).


This is what you need:

use String::Substitution qw( gsub_modify );

gsub_modify($string, $match, $substitue);

That assumes you don't actually need $1 outside of the replacement expression, and that you don't actually need $& and friends at all. If you do need them, then you can use the following:

use String::Substitution qw( interpolate_match_vars last_match_vars );

$string =~ s/$match/ interpolate_match_vars($substitute, last_match_vars()) /eg;

Upvotes: 2

Chris
Chris

Reputation: 1623

Obligatory discouragement: don't do this. Basically this is just running eval on a user-supplied string, which is really a bad idea.

Actual answer: use the ee modifer (see perlop) to s/// to eval the string in the right hand part of the expression:

$string =~ s/$match/"\"only $substitute\""/gee

By the way, you don't need to capture the pattern separately, just put the $match in a capturing group in the s/// expression:

$string =~ s/($match)/"\"only $substitute\""/gee

Upvotes: -1

Related Questions