CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Argument Passing: How To Get This Working

 



matteoguglielmi
Novice

Aug 18, 2014, 8:22 AM

Post #1 of 17 (2798 views)
Argument Passing: How To Get This Working Can't Post


Code
$> cat textfile  
111-111
222-222
333*333
444-444
555-555
$> perl -nle 'print /^\d+-(\d+)/ ? ${1} : $_' textfile
111
222
333*333
444
555
$> perl -nle 'BEGIN {$reg=shift; $str=shift} print /$reg/ ? $str : $_' '^\d+-(\d+)' '${1}' textfile
${1}
${1}
333*333
${1}
${1}


I'd expect the second perl command to reproduce the output of the first one, but it does not.

Why perl is not interpreting $str in the "right" way (and how can I make it doing so)?


FishMonger
Veteran / Moderator

Aug 18, 2014, 9:09 AM

Post #2 of 17 (2791 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

The value of $str is the literal string '${1}' and doesn't get interpolated as a var as you are expecting.

To get your expected results, you need to use string eval.


Code
print /$reg/ ? eval $str : $_


You may also need to remove the quotes around the args being passed. I don't have access to linux system at the moment but after adjusting the quotes this is what works on Windows.


Code
D:\test>perl -nle "BEGIN {$reg=shift; $str=shift;} print /$reg/ ? eval $str : $_" ^\d+-(\d+) ${1} textfile 
111
222
333*333
444
555



matteoguglielmi
Novice

Aug 18, 2014, 9:54 AM

Post #3 of 17 (2787 views)
Re: [FishMonger] Argument Passing: How To Get This Working [In reply to] Can't Post

Thanks!

In linux (bash) you do need single quotes to prevent parameter substitution, as shown here below:


Code
$> perl -nle 'BEGIN {$reg=shift; $str=shift} print /$reg/ ? eval $str : $_' -- '^\d+-(\d+)' '${1}' textfile 
111
222
333*333
444
555


It's also advisable to use the "bare double-dash" (--) which signifies the end of command options, after which only positional parameters are accepted:


Code
$> perl -nle 'BEGIN {$reg=shift; $str=shift;} print /$reg/ ? eval $str : $_' '-d' '${1}' textfile 

Loading DB routines from perl5db.pl version 1.33
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:0): BEGIN { require 'perl5db.pl' };LINE: while (<>) {chomp;
...



Code
$> perl -nle 'BEGIN {$reg=shift; $str=shift;} print /$reg/ ? eval $str : $_' -- '-d' '${1}' textfile 
111-111
222-222
333*333
444-444
555-555



(This post was edited by matteoguglielmi on Aug 18, 2014, 9:59 AM)


Laurent_R
Veteran / Moderator

Aug 18, 2014, 10:11 AM

Post #4 of 17 (2779 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

Why don't you simply hardcode $1 ?


matteoguglielmi
Novice

Aug 18, 2014, 10:20 AM

Post #5 of 17 (2778 views)
Re: [Laurent_R] Argument Passing: How To Get This Working [In reply to] Can't Post

Because both the regular expression ($reg) and the replacement string ($str) may change during the execution of the bash script in which that command is stored.

The actual (bash) line script looks like this:


Code
perl $oPTS -nle 'BEGIN {$reg=shift; $str=shift} print /$reg/ ? eval $str : $_' -- "$pERLPATTERN" "$lINE" "$fILE"


where both pERLPATTERN and lINE variables may change.


(This post was edited by matteoguglielmi on Aug 18, 2014, 10:26 AM)


Laurent_R
Veteran / Moderator

Aug 19, 2014, 11:05 AM

Post #6 of 17 (2730 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

I think I've succeeded to do what you want. Try this:

Code
$ echo ' 
111-111
222-222
333*333
444-444
555-555
' | perl -ne 'BEGIN {$reg=shift; $str=shift} if (/$reg/) {print eval("$str"), "\n"} else { print $_}' '^\d+-(\d+)' '$1'

111
222
333*333
444
555



Laurent_R
Veteran / Moderator

Aug 19, 2014, 11:50 AM

Post #7 of 17 (2724 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

I did not have time when I posted my previous post to try various alternatives, but this syntax closer to what you have also works fine:

Code
$ echo ' 
111-111
222-222
333*333
444-444
555-555
' | perl -ne 'BEGIN {$reg=shift; $str=shift} /$reg/? print eval($str), "\n" : print $_' '^\d+-(\d+)' '$1'

111
222
333*333
444
555


Or even this one:

Code
$ echo ' 
111-111
222-222
333*333
444-444
555-555
' | perl -ne 'BEGIN {$reg=shift; $str=shift} print /$reg/? eval($str)."\n" : $_' '^\d+-(\d+)' '$1'

111
222
333*333
444
555



matteoguglielmi
Novice

Aug 20, 2014, 4:27 AM

Post #8 of 17 (2719 views)
Re: [Laurent_R] Argument Passing: How To Get This Working [In reply to] Can't Post

Thanks, that's perfect. I've got all sorted out.


matteoguglielmi
Novice

Aug 20, 2014, 6:12 PM

Post #9 of 17 (2645 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

I spoke too early... how to eval $str in such a case?


Code
perl $oPTS -ple 'BEGIN {$reg=shift; $str=shift; $i=0} if (/$reg/ and $i==0) {s/$reg/$str/; $i++}' -- "$pERLPATTERN" "$lINE" "$fILE"



FishMonger
Veteran / Moderator

Aug 21, 2014, 6:04 AM

Post #10 of 17 (2593 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post


Code
s/$reg/eval $str/e;


See: perldoc perlre modifiers section
http://perldoc.perl.org/perlre.html#Modifiers


BillKSmith
Veteran

Aug 21, 2014, 6:58 AM

Post #11 of 17 (2568 views)
Re: [FishMonger] Argument Passing: How To Get This Working [In reply to] Can't Post

Ron,

is

Code
s/$reg/eval $str/e;

the same as this shorter form?

Code
s/$reg/$str/ee;

Good Luck,
Bill


FishMonger
Veteran / Moderator

Aug 21, 2014, 7:02 AM

Post #12 of 17 (2563 views)
Re: [BillKSmith] Argument Passing: How To Get This Working [In reply to] Can't Post

I believe it is, but didn't test it so I didn't want to post the shorter version if they weren't the same.


matteoguglielmi
Novice

Aug 21, 2014, 7:27 AM

Post #13 of 17 (2544 views)
Re: [FishMonger] Argument Passing: How To Get This Working [In reply to] Can't Post

The two commands may be equivalent indeed, but something is wrong:


Code
$> cat textfile  
111-111
222-222
333*333
444-444
555-555
$> perl -ple 'BEGIN {$reg=shift; $str=shift; $i=0} if (/$reg/ and $i==0) {s/$reg/eval $str/e; $i++}' -- '(\d+)' '${1}${1}' textfile
Scalar found where operator expected at (eval 1) line 1, near "${1}${1}"
(Missing operator before ${1}?)
-111
222-222
333*333
444-444
555-555
$> perl -ple 'BEGIN {$reg=shift; $str=shift; $i=0} if (/$reg/ and $i==0) {s/$reg/$str/ee; $i++}' -- '(\d+)' '${1}${1}' textfile
Scalar found where operator expected at (eval 1) line 1, near "${1}${1}"
(Missing operator before ${1}?)
-111
222-222
333*333
444-444
555-555


In fact, the expected output should be this one:


Code
$> perl -ple 'BEGIN {$i=0} if (/$reg/ and $i==0) {s/(\d+)/${1}${1}/; $i++}' -- textfile 
111111-111
222-222
333*333
444-444
555-555



(This post was edited by matteoguglielmi on Aug 21, 2014, 7:55 AM)


FishMonger
Veteran / Moderator

Aug 21, 2014, 9:19 AM

Post #14 of 17 (2505 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

Personally, I don't like using 1 liners except for simple one off tasks and never for important production code. One liners are more difficult to troubleshoot and maintain, especially when they start to get long and complicated. In every single case I've seen, one liner scripts lack proper error checking/handling.

Here's a working one liner.

Code
perl -ple 'BEGIN {$reg=shift; $str=shift; $cnt=shift;} last if $i; if(/$reg/) {s/$reg/eval($str) x $cnt/ee; $i++}' -- '(\d+)' '$1' 2 textfile


Here's how I'd do it (but with additional error checking).

Code
#!/usr/bin/perl 

use strict;
use warnings;
use Getopt::Long;

my $cnt = 1;
GetOptions (
"reg|r=s" => \my $pattern,
"str|s=s" => \my $replace,
"file|f=s" => \my $file,
"cnt|c=i" => \$cnt
) or die "Error in command line arguments\n";

open my $fh, '<', $file or die "failed to open '$file' <$!>";
while (<$fh>) {
s/$pattern/eval($replace) x $cnt/ee;
print;
}
close $fh;


Executed as:

Code
./script.pl -r '(\d+)' -s '$1' -c 2 -f textfile


If the plan is to do inplace editing like your other one liner examples, it would be an easy adjustment to the script to accommodate that need.


matteoguglielmi
Novice

Aug 21, 2014, 9:33 AM

Post #15 of 17 (2503 views)
Re: [FishMonger] Argument Passing: How To Get This Working [In reply to] Can't Post

Yes, I agree with you about one-liners usage, but I have to stick with them for this project.

I've also found a solution, here it is:


Code
$> perl -ple 'BEGIN {$reg=shift; $str=shift; $i=0} if (/$reg/ and $i==0) {eval("s/\$reg/$str/"); $i++}' -- '(\d+)' '${1}${1}' textfile  
111111-111
222-222
333*333
444-444
555-555


On the web I've also found "evil-eval" posts that suggest to read this book in order to avoid using it:


Quote
http://hop.perl.plover.com/book/pdf/HigherOrderPerl.pdf



(This post was edited by matteoguglielmi on Aug 21, 2014, 9:37 AM)


FishMonger
Veteran / Moderator

Aug 21, 2014, 9:42 AM

Post #16 of 17 (2499 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

Yes, that is an excellent book and is one I have yet to read.

Using eval can be dangerous becasue it can easily open big security holes if you're not very careful.


(This post was edited by FishMonger on Aug 21, 2014, 9:45 AM)


Laurent_R
Veteran / Moderator

Aug 21, 2014, 10:16 AM

Post #17 of 17 (2492 views)
Re: [matteoguglielmi] Argument Passing: How To Get This Working [In reply to] Can't Post

Just a word of caution: Higher Order Perl is a fantastic book, in my personal view probably the best computer science book I have read in the last ten years (and I read quite many each year), it's a book that has really changed my way of thinking about programming (not only in Perl), but it is not an easy book.

It is aimed at people having at a confirmed intermediate level in Perl. I've read most of it on line a couple of time, but I ended up buying the paper version so that I could work through it better and I certainly don't regret that decision.

I am not saying that you should buy the dead-tree version, though. First try to read it on line, to get an idea of it, and if you find it interesting but a bit difficult, then you might decide to purchase it as I eventually did.

On a completely different subject: I am wondering why you are passing such complicated fields as regexes from bash. I have the feeling that you'd be much better off making more in Perl and less in bash, and you would probably have much less trouble with argument passing.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives