1

I need to run a system command which would go to a directory and delete sub directories excluding files if present. I wrote the below command to perform this operation:

system("cd /home/faizan/test/cache ; for i in *\; do if [ -d \"$i\" ]\; then echo \$i fi done");

The command above keeps throwing syntax error. I have tried multiple combinations but still not clear how this should go. Please suggest.

f-z-N
  • 1,645
  • 4
  • 24
  • 38
  • error: sh: -c: line 1: syntax error: unexpected end of file – f-z-N Dec 26 '12 at 10:24
  • Why not create a bash file separately and then call it from your Perl program? – Chankey Pathak Dec 26 '12 at 10:24
  • This particular command needs to be executed on around 16 servers through ssh/perl. I need some way to perform this operation using a single perl script on multiple servers – f-z-N Dec 26 '12 at 10:27
  • You might be facing [this problem](http://stackoverflow.com/questions/6366530/bash-syntax-error-unexpected-end-of-file) – Chankey Pathak Dec 26 '12 at 10:33
  • Tried above but still the same error message. Somehow I feel that it is related to the way the command has been formed but I am not able to pinpoint the mistake. – f-z-N Dec 26 '12 at 10:39

4 Answers4

6

Well, your command line does contain syntax errors. Try this:

system("cd /home/faizan/test/cache ; for i in *; do if [ -d \"\$i\" ]; then echo \$i; fi; done");

Or better yet, only loop over directories in the first place;

system("for i in /home/faizan/test/cache/*/.; do echo \$i; done");

Or better yet, do it without a loop:

system("echo /home/faizan/test/cache/*/.");

(I suppose you will want to rmdir instead of echo once it is properly debugged.)

Or better yet, do it all in Perl. There is nothing here which requires system().

tripleee
  • 175,061
  • 34
  • 275
  • 318
1

As question title stand for system command, this will answer directly, but the sample command using bash contain only thing that will be simplier in perl only (take a look at other answer using opendir and -d in perl).

If you want to use system (instead of open $cmdHandle,"bash -c ... |"), the prefered syntax for execution commands like system or exec, is to let perl parsing the command line.

Try this (as you've already done):

perl -e 'system("bash -c \"echo hello world\"")'
hello world

perl -e 'system "bash -c \"echo hello world\"";'
hello world

And now better, same but letting perl ensure command line parsing, try this:

perl -e 'system "bash","-c","echo hello world";'
hello world

There are clearly 3 argument of system command:

  1. bash
  2. -c
  3. the script

or little more:

perl -e 'system "bash","-c","echo hello world;date +\"Now it is %T\";";'
hello world
Now it is 11:43:44

as you can see in last purpose, there is no double double-quotes enclosing bash script part of command line.

**Nota: on command line, using perl -e '...' or perl -e "...", it's a little heavy to play with quotes and double-quotes. In a script, you could mix them:

system 'bash','-c','for ((i=10;i--;));do printf "Number: %2d\n" $i;done';

or even:

system 'bash','-c','for ((i=10;i--;));do'."\n".
                       'printf "Number: %2d\n" $i'."\n".
                       'done';

Using dots . for concatening part of (script part) string, there are always 3 arguments.

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
1

You're still best off trying this as a bash command first. Formatting that properly makes it much clearer that you're missing statement terminators:

for i in *; do
    if [ -d "$i" ]; then
        echo $i
    fi
done

And condensing that by replacing new lines with semicolons (apart from after do/then):

for i in *; do if [ -d "$i" ]; then echo $i; fi; done

Or as has been mentioned, just do it in Perl (I haven't tested this to the point of actually uncommenting remove_tree - be careful!):

use strict;
use warnings;

use File::Path 'remove_tree';
use feature 'say';

chdir '/tmp';
opendir my $cache, '.';
while (my $item = readdir($cache)) {
    if ($item !~ /^\.\.?$/ && -d $item) {
        say "Deleting '$item'...";
        # remove_tree($item);
    }
}
Unk
  • 1,103
  • 6
  • 11
  • Thank you for the nice explanation. The problem is that only one server has perl installed and others dont where this has to be executed. I need to ssh to those servers using perl and then execute either a sh script or something similar to above. – f-z-N Dec 26 '12 at 10:58
1

Using system

my @args = ("cd /home/faizan/test/cache ; for i in *; do if [ -d \"\$i\" ]; then echo \$i; fi; done");
system(@args);

Using Subroutine

sub do_stuff {
  my @args = ( "bash", "-c", shift );
  system(@args);
}

do_stuff("cd /home/faizan/test/cache ; for i in *; do if [ -d \"\$i\" ]; then echo \$i; fi; done");
Chankey Pathak
  • 21,187
  • 12
  • 85
  • 133