http://qs1969.pair.com?node_id=866177

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

Hi All,
I have an array of keywords such as @a = qw(xyz, uvw, tid, bnjuw)
I want to run the Unix find command on each one of these keywords using a Perl script as:
foreach my $k ( @a) { my $name = $k.\*; $x = `find . -name "$name" -print`; }
But Perl gives an error saying "Scalar found where operator expected".
Please tell me what I am doing wrong? I am new to Perl so please help me.
Sally Field

Replies are listed 'Best First'.
Re: passing a variable value to Unix command
by runrig (Abbot) on Oct 19, 2010 at 22:09 UTC
    my $name = $k.\*;
    should be:
    my $name = $k . "*";
    or:
    my $name = "$k*";
    Also qw expects whitespace separated arguments, so I suspect you don't want the commas in there.
Re: passing a variable value to Unix command
by ikegami (Patriarch) on Oct 20, 2010 at 00:15 UTC

    I had a hard time generating that error.

    $ find . -name "doesn't exist" -print $ find . -name "" -print $ find . -name -print $ find . -name find: missing argument to `-name'

    There's no way the command you're executing could generate that error with my find. Maybe if $k contained a newline and you hadn't used quotes.

    Anyway, if you want to avoid unintentional interpolation, use IPC::System::Simple's capturex.

    my $output = capturex(find => ( -name => "$k*", -print ));

    By the way, "\*" is the same as "*".

Re: passing a variable value to Unix command
by graff (Chancellor) on Oct 20, 2010 at 02:23 UTC
    Depending on how many patterns you need to locate, and how long it takes for unix 'find' to traverse the given directory tree, you might want to consider running 'find' just once, and use perl's grep function to pull out the desired file names:
    my $file_regex = join( '|', @a ); my @found = grep /^(?:$file_regex)\./, `find . -print`;
    (BTW, I think '-print' is on by default -- you probably don't need to include that in the 'find' command.)
Re: passing a variable value to Unix command
by JavaFan (Canon) on Oct 20, 2010 at 01:50 UTC
    foreach my $k (@a) { my $x = `find . -name $k.* -print`; ... do something with $x ...; }
Re: passing a variable value to Unix command
by pobocks (Chaplain) on Oct 19, 2010 at 23:38 UTC

    I'm not able to replicate your error; however, there are a few errors/potential errors in your code (at least as written).

    In the array of keywords, the comma is wrong unless you mean it to be part of the pattern. "use warnings" catches this.

    If you're using lexical variables, $x and @a need a "my" in front of them when declared. "use strict" catches this.

    Here's the code with these corrections, and with strict and warnings turned on. It works on my system, but then again, so does the uncorrected code.

    #!/usr/bin/perl use strict; use warnings; my @a = qw(xyz uvw tid bnjuw); foreach my $k ( @a) { my $name = $k."\*"; my $x = `find . -name "$name" -print`; }
    for(split(" ","tsuJ rehtonA lreP rekcaH")){print reverse . " "}print "\b.\n";
Re: passing a variable value to Unix command
by mjscott2702 (Pilgrim) on Oct 20, 2010 at 08:18 UTC
    Also, remember that Perl has its own version of find, and you can even get Perl to write the script for you:

    # find all files modified in past 24 hours and do a line count

    find2perl . -mtime -1 -exec wc -l {} \;

Re: passing a variable value to Unix command
by DrHyde (Prior) on Oct 20, 2010 at 10:06 UTC

    First, if you want to append a * to the value, it needs to be quoted:

    my $name = $k."*";

    Second, running that command several times, once for each element in the list, can be veeeeerrrryyyyy ssllllloooooooowwww. Most (all?) platforms' find utilities will let you do something like this ...

    my $args = join(" -o ", map { "-name \"$_*\" -print" } @a); $x = `find . $cmd`;
    and do it all in one go. Although obviously at some point you're going to run into command line length limitations.