How can I pass a substitution pattern on the command line?

P

P B

I'd like to create a (Linux) perl command line utility that creates
subdirectories based on a common part of several filenames and then
moves the corresponding files into them. The command would (ideally)
look something like this:

makesubdirs.pl 's/^([a-zA-Z+)_\d{2}\.[a-zA-Z]{3}$/$1/' *

If it was issued in a directory containing, for example, the following
files:

image01.jpg
image02.jpg
movie01.mpg
movie02.mpg

it would create an 'image' subdirectory and a 'movie' subdirectory and
move the files, etc., you get the idea.

So, how can I pass the whole s/// operator to the program, to be used
(presumably) thusly (to continue the example used above):

my $pattern = shift @ARGV;
my $subdirectory =~ $pattern;

.... and so on to create the subdirectories, etc.?

Thank you.
 
A

A. Sinan Unur

I'd like to create a (Linux) perl command line utility that creates
subdirectories based on a common part of several filenames and then
moves the corresponding files into them. The command would (ideally)
look something like this:

makesubdirs.pl 's/^([a-zA-Z+)_\d{2}\.[a-zA-Z]{3}$/$1/' *

If it was issued in a directory containing, for example, the following
files:

image01.jpg
image02.jpg
movie01.mpg
movie02.mpg

it would create an 'image' subdirectory and a 'movie' subdirectory and
move the files, etc., you get the idea.

So, how can I pass the whole s/// operator to the program, to be used
(presumably) thusly (to continue the example used above):

First, you don't need substitution. You need to capture matches.

Second, just pass the pattern string to the program.

[sinan@kas ~]$ cat s.pl
#!/usr/bin/perl

use strict;
use warnings;

my $pattern = shift @ARGV;
my $re = qr/$pattern/;

for my $arg ( @ARGV ) {
if ( my @parts = ( $arg =~ $re ) ) {
my $subdir = join q{}, @parts;
# put actual code to mkdir, move etc
print "$arg goes in $subdir\n";
}
}

__END__

[sinan@kas ~]$ perl s.pl '\.(\w{1,3})$' *
wallpaper.png goes in png
test.zip goes in zip
etc.zip goes in zip
s.pl goes in pl
t.pl goes in pl
www.zip goes in zip


--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
P

P B

First, you don't need substitution. You need to capture matches.
Second, just pass the pattern string to the program.
[sinan@kas ~]$ cat s.pl
#!/usr/bin/perl
use strict;
use warnings;
my $pattern = shift @ARGV;
my $re = qr/$pattern/;
for my $arg ( @ARGV ) {
if ( my @parts = ( $arg =~ $re ) ) {
my $subdir = join q{}, @parts;
# put actual code to mkdir, move etc
print "$arg goes in $subdir\n";
}
}

[sinan@kas ~]$ perl s.pl '\.(\w{1,3})$' *
wallpaper.png goes in png
test.zip goes in zip
etc.zip goes in zip
s.pl goes in pl
t.pl goes in pl
www.zip goes in zip

Very Nice. Thank you. I have something similar (though much, much
cruder, and probably much slower) working now, but I'll put your
suggestions to good use.

Now if you don't mind, for my edification, two questions:

What is the 'if' statement testing? What is
( @parts = ( $arg =~ $re ) )
doing? What values is @parts being populated with?

What exactly is the q{} operator doing in the join statement? What is
its content, so to speak? Is it just the same as '' here?

Thanks again for your advice. I'm slowly picking up 'idiomatic perl', so
I'm always eager to learn new things.


On a side note, how /would/ one pass a whole s/// operator on the
command line (sed-style, I guess), supposing you wanted to do
interesting things with backreferences, the g and i modifiers, etc.?
 
J

John W. Krahn

P said:
First, you don't need substitution. You need to capture matches.
Second, just pass the pattern string to the program.
[sinan@kas ~]$ cat s.pl
#!/usr/bin/perl
use strict;
use warnings;
my $pattern = shift @ARGV;
my $re = qr/$pattern/;
for my $arg ( @ARGV ) {
if ( my @parts = ( $arg =~ $re ) ) {
my $subdir = join q{}, @parts;
# put actual code to mkdir, move etc
print "$arg goes in $subdir\n";
}
}

[sinan@kas ~]$ perl s.pl '\.(\w{1,3})$' *
wallpaper.png goes in png
test.zip goes in zip
etc.zip goes in zip
s.pl goes in pl
t.pl goes in pl
www.zip goes in zip

Very Nice. Thank you. I have something similar (though much, much
cruder, and probably much slower) working now, but I'll put your
suggestions to good use.

Now if you don't mind, for my edification, two questions:

What is the 'if' statement testing? What is
( @parts = ( $arg =~ $re ) )
doing? What values is @parts being populated with?

$re is the regular expression '\.(\w{1,3})$'. $arg is a file name. $re
is matched against $arg and everything inside capturing parentheses is
returned and stored in @parts. If @parts is empty then it is false and
the next file name is processed.
What exactly is the q{} operator doing in the join statement? What is
its content, so to speak? Is it just the same as '' here?

q{} is exactly the same as ''.
Thanks again for your advice. I'm slowly picking up 'idiomatic perl', so
I'm always eager to learn new things.


On a side note, how /would/ one pass a whole s/// operator on the
command line (sed-style, I guess), supposing you wanted to do
interesting things with backreferences, the g and i modifiers, etc.?

perldoc -q "How can I expand variables in text strings"



John
 
P

P B

[snipped A. Sinan Unur's example]
$re is the regular expression '\.(\w{1,3})$'. $arg is a file name. $re
is matched against $arg and everything inside capturing parentheses is
returned and stored in @parts. If @parts is empty then it is false and
the next file name is processed.
q{} is exactly the same as ''.
perldoc -q "How can I expand variables in text strings"

Many thanks to both A. Sinan Unur and John W. Krahn for your helpful examples
and explanations. I've incorporated them into my script and it's working
much more reliable and fast now.
 
S

sln

[snipped A. Sinan Unur's example]
$re is the regular expression '\.(\w{1,3})$'. $arg is a file name. $re
is matched against $arg and everything inside capturing parentheses is
returned and stored in @parts. If @parts is empty then it is false and
the next file name is processed.
q{} is exactly the same as ''.
^^^^^^^^^^
You can't pass that form via string and expect it to work on the replacement
side (ie: s/pattern/replacement/) without doing an eval on it within the script.

Also, one must be carefull of shell interactions.
Example:
windows - perl hh.pl 'arg1'. $ARGV[0] is '<quote>arg1<quote>'
windows - perl hh.pl arg1. $ARGV[0] is 'arg1'
windows - perl hh.pl "arg1". $ARGV[0] is 'arg1'
windows - perl hh.pl arg1 and more. $ARGV[0] is 'arg1'
windows - perl hh.pl "arg1 and more". $ARGV[0] is 'arg1 and more'
---
use strict;
use warnings;

my $pattern = shift @ARGV;
my $string = q/take MEME out/;

print "\"$string\" =~ $pattern\n";

eval "\$string =~ $pattern";

print $string,"\n";

__END__


c:\temp>perl aa.pl "s/(ME)\1/$1/"

"take MEME out" =~ s/(ME)\1/$1/
take ME out

c:\temp>


-sln
 
P

P B

^^^^^^^^^^ You can't pass that form via string and expect it
to work on the replacement side (ie: s/pattern/replacement/)
without doing an eval on it within the script.

Thanks for the bit about the eval. That fills in the blanks on how to
make the s/// argument work with backreferences.
Also, one must be carefull of shell interactions.
Example:
windows - perl hh.pl 'arg1'. $ARGV[0] is '<quote>arg1<quote>'
windows - perl hh.pl arg1. $ARGV[0] is 'arg1'
windows - perl hh.pl "arg1". $ARGV[0] is 'arg1'
windows - perl hh.pl arg1 and more. $ARGV[0] is 'arg1'
windows - perl hh.pl "arg1 and more". $ARGV[0] is 'arg1 and more'

Noted. I do work with ActivePerl in Windows occasionally, but I intend
to use this method exclusively in a Unix-like environment.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top