Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

mmv-like hack in perl?

by mpd (Monk)
on Apr 14, 2003 at 01:36 UTC ( #250192=perlquestion: print w/replies, xml ) Need Help??

mpd has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm working on something that works similar to mmv, but is more suited to the job i need done. I'd like to cheat using perl. the syntax i'd like to get is something like: $ pmmv (.+)-(\d{,2})\.ext moof-$1-$2.newext

getting the files to be moved is no problem, but is there an easy way to translate the $1, etc given on the command line to the value matched in the regexp? My results getting the $1 to evaluate to the first match instead of the literal string have so far have been unsuccessful. Any pointers?

Replies are listed 'Best First'.
•Re: mmv-like hack in perl?
by merlyn (Sage) on Apr 14, 2003 at 01:42 UTC
    This won't work:
    my $pattern = q/(...)(...)/; my $replace = q/$2-$1/; s/$pattern/$replace/g;
    because the $replace is inserted into the "double-quoted" string on the right side, and not again rescanned to see if it has any variables to be replaced. So you get a literal $1 and so on.

    However, if you trust your invoker, you could try something like:

    my $pattern = q/(...)(...)/; my $replace = q/$2-$1/; s/$pattern/qq{$replace}/eeg;
    as long as the curly braces balance nicely.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      Thank you for your help. I think I'm still having a problem with the line:


      Here's the snippet that's failing:

      # get strings from GUI. my $old = my $new = $_->children->get; # get old filename my $pattern = $form->{'entry2'}->get_text(); # e.g. $pattern == "^(\d{2})\. (.*)$" after this my $replace = $form->{'entry1'}->get_text(); # e.g. $replace == "two-$2, one-$1" after this # is the following match necessary? $1, etc # need to be assigned somehow... if($old =~ /$pattern/) { $new =~ s/$pattern/qq{$replace}/eeg; print STDERR $old." => ".$new."\n"; }

      After the $new =~ line, $new is empty, every time. Am I missing something? Thanks again

        $new = $old; $new =~ s/$pattern/qq{$replace}/eeg;
        But you're scaring me here. I said that the string had to be from a trusted source. As soon as you start talking "GUI", that makes me think that the user-ID of the person typing the string is not necessarily the user-ID of the person running the code.

        Let me reemphasize. Using this code as-is will allow any arbitrary Perl code to be executed, including shelling out to execute arbitrary system commands. Clear? It's not just about mangling a string. You must either trust the invoker, or not use this code.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

Re: mmv-like hack in perl? (don't use s///)
by Aristotle (Chancellor) on Apr 14, 2003 at 11:23 UTC

    There's no easy way to do this save for parsing the replace-with string yourself. There's a rename script which comes with Perl, that allows you to pass Perl code as the first parameter, which it then executes for every file, passing the filename in $_ and moving the file if the code modified $_.

    Note that $1 et al are most likely subject to parsing by the shell on Unixoid systems, as are parens and the backslash, so if you want to use them, you'll need to enclose the parameters in single quotes to prevent those characters from being interpreted by the shell.

    Probably the sanest solution would be to use a printfish syntax for the right side, composing a new string from the captured bits for every match. Something like this (untested; esp. the pattern).

    my ($re, $fmt) = @ARGV; function reformat { local $_ = $fmt; s/%(?:(\d+)|.)/$_[$1] if defined $1/ge; return $_; } # ... $re = qr/$re/; # precompile for(@list_of_files) { next unless (my @capture = /$re/); rename $_, reformat(@capture); }
    You'd then call it something like foo '(.+)-(\d{,2})\.ext' moof-%1-%2.newext, using %% to use literal percent signs in the replace-with name.

    Makeshifts last the longest.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://250192]
Approved by Courage
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (1)
As of 2021-12-08 03:20 GMT
Find Nodes?
    Voting Booth?
    R or B?

    Results (34 votes). Check out past polls.