Pattern Matching from a OS command

R

Ricky

Hi,

Quite new to perl so this is probably easy.....I'm trying to carry out
a command which lists some unix files (number of which are unknown) and
return only the pattern matched....

i.e,


my @files = (`ls $user1\_\*`) ;

and then apply the following pattern to the above:

/$user1\_(\S+)/

to grab the string which is on the right hand side of the underscore.
So, with

ricky_testpage.data
ricky_testpage2.data

@files would end up with

testpage.data
testpage2.data

How can I do this?

Thank you!
 
P

Paul Lalli

Ricky said:
Quite new to perl so this is probably easy.....I'm trying to carry out
a command which lists some unix files (number of which are unknown) and
return only the pattern matched....

i.e,
my @files = (`ls $user1\_\*`) ;

Neither of the _ nor * have to be escaped in a double-quotish string.
However, the underscore will be taken as part of the variable, so it's
best (IMO, anyway) to explicitly delimit the variable:

my @files = `ls ${user1}_*`;
and then apply the following pattern to the above:

/$user1\_(\S+)/

to grab the string which is on the right hand side of the underscore.
So, with

ricky_testpage.data
ricky_testpage2.data

@files would end up with

testpage.data
testpage2.data

How can I do this?

I wouldn't bother shelling out to an external program like ls. I would
just use glob to get the files:

my @files = glob "${user1}_*";

and then use a pattern match with the map() function to take off the
piece you don't want:

@files = map { s/${user1}_ // } @files;

Or, if you prefer, combine both steps into one:

my @files = map { s/${user1}_// } glob "${user1}_*";

Here's another alternative that uses the opendir and readdir functions
instead:

opendir my $dh, '.' or die "Can't open current directory: $!";
my @files;
while (my $file = readdir($file)){
push @files, /^${user1}_(\S+)/;
}

In this last example, the pattern match is being called in a list
context. If it succeeds (ie, the current file matched), the contents
of the capturing parenthesis are returned and pushed onto @files. If
it didn't, an empty list is returned, and so nothing is added to @files
for that file entry.

For more information:
perldoc -f opendir
perldoc -f readdir
perldoc -f map
perldoc -f glob
perldoc perlop (for the pattern matching operator)

Hope this helps,
Paul Lalli
 
A

Anno Siegel

Ricky said:
Hi,

Quite new to perl so this is probably easy.....I'm trying to carry out
a command which lists some unix files (number of which are unknown) and
return only the pattern matched....

i.e,


my @files = (`ls $user1\_\*`) ;

I'll assume you are aware of the consequences of using the external
ls command.
and then apply the following pattern to the above:

/$user1\_(\S+)/

to grab the string which is on the right hand side of the underscore.
So, with

ricky_testpage.data
ricky_testpage2.data

@files would end up with

testpage.data
testpage2.data

perldoc -f map

Anno
 
R

Ricky

Sorry, I do have one more question.... This bit of code

my @files = glob "${user1}_*";

@files = map { s/${user1}_ // } @files;

produces this warning: "my" variable @files masks earlier declaration
in same scope at ./syncProfiles2.pl line 130. I guess because I am
defining @files twice.

I then print the output of @files by:

foreach (@files) {
print "$_\n";
}
print "\nFinished\n";

and I receive a "1" for each pattern match rather than the string. I
took a look at perldoc -f map but can't see how to get the string back?
 
D

Dr.Ruud

Ricky schreef:
Hi,

Quite new to perl so this is probably easy.....I'm trying to carry out
a command which lists some unix files (number of which are unknown)
and return only the pattern matched....

i.e,


my @files = (`ls $user1\_\*`) ;

and then apply the following pattern to the above:

/$user1\_(\S+)/

to grab the string which is on the right hand side of the underscore.
So, with

ricky_testpage.data
ricky_testpage2.data

@files would end up with

testpage.data
testpage2.data

How can I do this?


#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my $user1 = 'ricky';
my $mask = "\Q${user1}_\E";

my @files =
map /^${mask}(\S+)/, grep -f, <${mask}*>;

print Data::Dumper->Dump( [ $mask, \@files ]
, [ qw( mask *files ) ]
);
__END__

Beware: "ricky_a b c.txt" --> "a".
 
P

Paul Lalli

Ricky said:
Sorry, I do have one more question....

Please quote some context when posting a reply. Please read the
Posting guidelines for this group. Failure to do so will encourage
many of the most helpful people in this group to ignore your posts.
This bit of code

my @files = glob "${user1}_*";
@files = map { s/${user1}_ // } @files;

produces this warning: "my" variable @files masks earlier declaration
in same scope at ./syncProfiles2.pl line 130. I guess because I am
defining @files twice.

Well don't do that. Why and where are you defning @files previous to
this?
I then print the output of @files by:

foreach (@files) {
print "$_\n";
}
print "\nFinished\n";

and I receive a "1" for each pattern match rather than the string. I
took a look at perldoc -f map but can't see how to get the string back?

Whoops. That's what I get for not testing code I post. Yes, map
populates the array with the return values of the operation. I should
have written:

s/${user1}_// for @files;

My apologies.

Paul Lalli
 
R

Ricky

Paul said:
Please quote some context when posting a reply. Please read the
Posting guidelines for this group. Failure to do so will encourage
many of the most helpful people in this group to ignore your posts.


Well don't do that. Why and where are you defning @files previous to
this?

It was being defined twice in the code you gave initially.

my @files = glob "${user1}_*";
@files = map { s/${user1}_ // } @files;


Whoops. That's what I get for not testing code I post. Yes, map
populates the array with the return values of the operation. I should
have written:

s/${user1}_// for @files;

Now working perfectly, thanks!
 
P

Paul Lalli

Ricky said:
It was being defined twice in the code you gave initially.

my @files = glob "${user1}_*";
@files = map { s/${user1}_ // } @files;

You're right, but not the way you think you are. It *is* being
"defined" there twice. However, I originally mispoke. I should have
said "Why and where are you *declaring* @files previous to this?" It
is the prior declaration that is causing the warning. There is only
one "my" in my code. You must have another "my @files" elsewhere in
the code you haven't shown us.

Paul Lalli
 
D

Dr.Ruud

Paul Lalli schreef:

my @files = map { s/${user1}_// } glob "${user1}_*";

Why use substitution?

my @files =
map /^\Q${user1}\E(\S+)$/, grep -f, <\Q${user1}\E*>;

Notice the anchors, the quoting, the -f.

The anchors are there to prevent unwanted matches, the quotes are there
to disarm userids with special characters like punctuation, the -f is
there to only process plain files.
 
U

Uri Guttman

PL> @files = map { s/${user1}_ // } @files;

i believe that modifies @files in place and then overwrites it with
1's. but i could be wacked out on crack today.

PL> Or, if you prefer, combine both steps into one:

PL> my @files = map { s/${user1}_// } glob "${user1}_*";

umm, s/// returns a count of substitutions made. you need '; $_' at the
end of map block.

PL> Here's another alternative that uses the opendir and readdir functions
PL> instead:

PL> opendir my $dh, '.' or die "Can't open current directory: $!";
PL> my @files;
PL> while (my $file = readdir($file)){
PL> push @files, /^${user1}_(\S+)/;
PL> }

that could be done with map too (and properly :)

my @files = map { /^${user1}_(\S+)/ } glob "${user1}_*" ;

uri
 
D

Dr.Ruud

Dr.Ruud schreef:
map /^\Q${user1}\E(\S+)$/, grep -f, <\Q${user1}\E*>;

I forgot to re-include the underscores:

map /^\Q${user1}_\E(\S+)$/, grep -f, <\Q${user1}_\E*>;

I chose the expression variant of map, because I saw no need to for a
code block.
 
P

Paul Lalli

Uri said:
PL> @files = map { s/${user1}_ // } @files;

i believe that modifies @files in place and then overwrites it with
1's. but i could be wacked out on crack today.

PL> Or, if you prefer, combine both steps into one:

PL> my @files = map { s/${user1}_// } glob "${user1}_*";

umm, s/// returns a count of substitutions made. you need '; $_' at the
end of map block.

Yes, please see my correction elsewhere in this thread.
PL> Here's another alternative that uses the opendir and readdir functions
PL> instead:

PL> opendir my $dh, '.' or die "Can't open current directory: $!";
PL> my @files;
PL> while (my $file = readdir($file)){
PL> push @files, /^${user1}_(\S+)/;
PL> }

that could be done with map too (and properly :)

my @files = map { /^${user1}_(\S+)/ } glob "${user1}_*" ;

Yes, it could. My intent was to give another example that does the
same thing (assuming the original example had actually worked), but
looks remarkably different. Trying to show off TIMTOWTDI, basically...

Paul Lalli
 
T

Tad McClellan

Uri Guttman said:
but i could be wacked out on crack today.


Then if you want to fit in, you should tack a digit onto the
end of your name.

(Pick the one that was discovered much later than most of
the other digits.)

HTH
 

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

No members online now.

Forum statistics

Threads
474,184
Messages
2,570,973
Members
47,529
Latest member
JaclynShum

Latest Threads

Top