I think the literals are being passed to the subroutine instead of the regex.
Say what?
A literal is a piece of code. It cannot be passed to a subroutine. It can just be parsed and evaluated.
The string literal «q{^$_}» produces the three character string «^$_».
This string is placed in variable $pattern, to be interpolated by another string literal, «qx( grep $pattern /etc/passwd )». When $pattern contains «^$_», this literal produces the string « grep ^$_ /etc/passwd» which is then executed as a shell command.
Upon receipt of the command « grep ^$_ /etc/passwd», the shell will proceed to interpolate the value of $_ into the command, producing the string « grep ^/bin/sh /etc/passwd». It then proceeds to execute grep with arguments «^/bin/sh» and «/etc/passwd».
#!/usr/bin/perl use strict; use warnings; sub text_to_shell_lit(_) { return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/; my $s = $_[0]; $s =~ s/'/'\\''/g; return "'$s'"; } sub get_data { my ($pattern) = @_; my $pattern_lit = text_to_shell_lit($pattern); return qx( grep $pattern_lit /etc/passwd ); } my @ids = qw( john james ); { # Assumes each of @ids are "safe". my $pattern = '^\\(' . join('\\|', @ids) . '\\)'; my $permission = get_data($pattern); print($permission); } { # Assumes each of @ids are "safe" and match /^\w/ and /\w\z/. my $pattern = '\b\\(' . join('\\|', @ids) . \\)\b'; my $permission = get_data($pattern); print($permission); }
Better yet, avoid the shell and add error checking with the use of IPC::System::Simple.
#!/usr/bin/perl use strict; use warnings; use IPC::System::Simple qw( capturex ); sub get_data { my ($pattern) = @_; return capturex('grep', $pattern, '/etc/passwd'); } my @ids = qw( john james ); { # Assumes each of @ids are "safe". my $pattern = '^\\(' . join('\\|', @ids) . '\\)'; my $permission = get_data($pattern); print($permission); } { # Assumes each of @ids are "safe" and match /^\w/ and /\w\z/. my $pattern = '\b\\(' . join('\\|', @ids) . \\)\b'; my $permission = get_data($pattern); print($permission); }
Much better yet to simply avoid creating another process entirely.
#!/usr/bin/perl use strict; use warnings; sub get_etc_passwd { open(my $fh, '<', '/etc/passwd') or die $!; return <$fh>; } my @ids = qw( john james ); my @etc_passwd = get_etc_passwd(); { my $pattern = join('|', map quotemeta, @ids); my $re = qr/^(?:$pattern)/; print(grep /$re/, @etc_passwd); } { my $pattern = join('|', map quotemeta, @ids); # Assumes each of @ids match /^\w/ and /\w\z/. my $re = qr/\b(?:$pattern)\b/; print(grep /$re/, @etc_passwd); }
In reply to Re: Passing Regex Pattern in Subroutine
by ikegami
in thread Passing Regex Pattern in Subroutine
by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |