-1

I want to run this command in perl

for dir in *; do
 test -d "$dir" && ( find "$dir" -name '*test' | grep -q . || echo "$dir" );
 done

I have tried :

 system ("for dir in *; do
        test -d "\$dir" && ( find "\$dir" -name '*test' | grep -q . || echo "\$dir" );
        done");

but does not work .

shaq
  • 799
  • 1
  • 7
  • 12
  • 4
    That shell code is easily implemented in Perl. It is wrong to involve several different languages unless it is necessary – Borodin Aug 20 '12 at 11:04

4 Answers4

3

A pure Perl implementation using File::Find module's find function:

#!/usr/bin/env perl

use strict;
use warnings;

use File::Find;

find \&find_directories, '.';

sub find_directories {
    if ( -d && $File::Find::name =~ /test$/ ) {
        print "$File::Find::name\n";
    }
}
Alan Haggai Alavi
  • 72,802
  • 19
  • 102
  • 127
  • Thanks a lot , but the point is that I want to use shell script command in my Perl:) program – shaq Aug 20 '12 at 11:36
1

Your quoting is off.

"for dir in *; do
    test -d "\$dir" && ( find "\$dir" -name '*test' | grep -q . || echo "\$dir" );
    done"

You have decided to delimit your string with double quotes ", but they are included in your string.

Either escape the other quotes:

"for dir in *; do
    test -d \"\$dir\" && ( find \"\$dir\" -name '*test' | grep -q . || echo \"\$dir\" );
    done"

(error prone, ugly)

… or use another delimiter: Perl offers you a wide range of possibilities. These quoting syntaxes interpolate variables inside: "…" and qq{…} where you can use any character in [^\s\w] as delimiter, and non-interpolating syntaxes are: '…' and q{…} with the same delimiter flexibility as before:

qq{for dir in *; do
    test -d "\$dir" && ( find "\$dir" -name '*test' | grep -q . || echo "\$dir" );
    done}

The q and qq constructs can include the delimiter inside the string, if the occurrence is balanced: q( a ( b ) c ) works.

The third quoting mechanism is a here-doc:

system( <<END_OF_BASH_SCRIPT );
for dir in *; do
    test -d "\$dir" && ( find "\$dir" -name '*test' | grep -q . || echo "\$dir" );
    done
END_OF_BASH_SCRIPT

This is usefull for including longer fragments without worrying about a delimitor. The String is ended by a predefined token that has to appear on a line of its own. If the delimitor declaration is placed in single quotes (<<'END_OF_SCRIPT'), no variables will be interpolated:

system( <<'END_OF_BASH_SCRIPT' );
for dir in *; do
    test -d "$dir" && ( find "$dir" -name '*test' | grep -q . || echo "$dir" );
    done
END_OF_BASH_SCRIPT

Note on the q{} and qq{} syntax: This is a feature never to be used outside of obfuscation, but it is possible to use a character in \w as the delimiter. You have to include a space between the quoting operator q or qq and the delimiter. This works: q xabcx and is equal to 'abc'.

amon
  • 57,091
  • 2
  • 89
  • 149
  • I removed the $ , and instead of "" I have used qq as you mentioned,still complains – shaq Aug 20 '12 at 11:35
  • @shaq What part of this does not work? Do you get a *syntax error* in Perl, or does it fail at run time or does the shell script fail? What does the error message say? The last code fragment compiles all right with me. – amon Aug 20 '12 at 11:57
0

Instead of starting the script, try starting a bash instance that runs the script. E.g.

system("bash -c 'for dir bla bla bla'");
Sjoerd
  • 74,049
  • 16
  • 131
  • 175
0

system() uses your default system shell, which is probably not Bash. The solution is to call Bash explicitly with the system() command.

Community
  • 1
  • 1
dan1111
  • 6,576
  • 2
  • 18
  • 29