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

im trying to open a perl program from within a perl program. The program im trying to run is to run with the "&" argument so that it runs in the background. both programs are in the same directory.
chdir($current_dir) or die "cant change\n"; my $dir = $current_dir . "/program2.pl"; my @args = ("$dir", "&"); system (@args);
what am i doing wrong? im sorry if this is stupid question but ive started learning perl very recently.

Replies are listed 'Best First'.
Re: running programs from PERL
by afoken (Chancellor) on Oct 25, 2009 at 09:19 UTC
    • Your code lacks error checks on system().
    • Your code does not give a useful error message should chdir fail. Include $! in die.
    • There is no need to interpolate $dir in constructing @args. There is also no need to use interpolating quotes on a constant string. my @args=($dir,'&') is sufficient.
    • The temporary @args array is not needed, use system($dir,'&').
    • The "&" is passed as a literal argument to program2.pl. If you want THE SHELL to put program2.pl in background, you need to invoke the shell by calling system with a single string argument. That causes a lot of trouble, starting with the need to use proper quoting for an unknown shell that can require different quoting on different systems. So, your chances to invoke "the" shell with proper quoting are quite low, and thus, you open a big security hole.
    • To create a background process, use fork() and exec() as explained in the perl documentation. On Windows, use system(1,...).

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      The temporary @args array is not needed, use system($dir,'&').

      That's right. But it doesn't do much harm either... And in case you want to debug what is actually being passed to system, you can simply add a print @args without restructering the code, instead of duplicating the argument list and trying to keep both in sync when you make changes. This is especially handy with more unwieldy (OT: or would you say unwieldier?) argument lists. You never know when you'll need it...

      my $prog = 'myprog'; my $file = 'myfile'; my @useropts = qw(-bar -baz); my @args = ("/path/to/$prog", '-foo', @useropts, $file, '-o', "$file.o +ut"); print "system(): @args\n"; # debug system (@args); # vs. print join(" ", "system():", "/path/to/$prog", '-foo', @useropts, $fil +e, '-o', "$file.out"), "\n"; # debug system("/path/to/$prog", '-foo', @useropts, $file, '-o', "$file.out");
Re: running programs from PERL
by jakobi (Pilgrim) on Oct 25, 2009 at 10:10 UTC

    Beyond Alexander's tips, there's one more thing that bugs me:

    You chdir to $current_dir, then prepend $current_dir/ to your command. Works nicely on Unix for $current_dir being absolute or . or ./. . But for "" or a non-trivial relative path, you're in for a surprise... .

    One way to cope is prepending $ENV{PWD}/ to a relative path. Note that $ENV{PWD} isn't updated by chdir(), being set by the shell. Note 2: Better yet, check Anonymous' File::chdir pointer below and prepend $CWD instead (thx, this elimininates most of the chdir pains! Note2Self: my($CWD) stops the chdir side effect of assigning. Good.).


    Ad afoken's warning on using the shell:

    If you restrict yourself to Unix (and CYGWIN), you normally can assume at least a Bourne-style or POSIX shell, which allows a nice idiom using %ENV to avoid severe secure quoting headaches: $ENV{f}="...";system qq{ls -l -- "\$f"};.

    Open Question: Windows processes should support %ENV as part of their POSIX support. What is be the corresponding secure Windows-NON-CYGWIN-idiom for the Unix shell's variable interpolation w/o word splitting, i.e. "$f"?

    cu & HTH, Peter -- hints may be untested unless stated otherwise; use with caution & understanding.
      Open Question: Windows processes should support %ENV as part of their POSIX support. What is be the corresponding secure Windows-NON-CYGWIN-idiom for the Unix shell's variable interpolation w/o word splitting, i.e. "$f"?

      Windows processes do have an environment block, but it is nothing to do with POSIX support. Do not confuse the operating system with the shell - Korn shell 93, for example (via uwin) runs on Windows. It is not that difficult to write a shell which runs on UNIX and Windows (I have done it, so it can't be hard).

      The Microsoft cmd.exe shell only uses double-quotes (as does awk) but does not use the $ operator to get a variable value, as is common in some shells, but it uses the % delimiter, as in %PATH%. Coming from a UNIX background I think it is safe to say that cmd.exe does not support interpolation as we know it. By the way, environment variables in Windows are not case-sensitive, so %PATH% is the same as %path% (unlike the c-shell). For example:
      C:\>set fred=42 C:\>perl -e "print \"$ENV{FRED}\n\"" 42
      Cygwin (and uwin) makes Windows environment variables UPPERCASE, and is case-sensitive.

        With POSIX support I meant the libc and lower portions of POSIX and I was under the impression that e.g POSIX exec() was part of whatever was once enough to give Microsoft some claim of POSIX compatibility certifications for NT and later. Looks like I badly misremembered things.

        My original question is the reverse of your example:

        Can I e.g. set $ENV{VARIABLE} in a non-CYGWIN-port of Perl, and then use system q{dir "%VARIABLE%"} to have cmd.exe expand the variable? More specifically, what happens if the variable contains [\n \\;"']?

        A new question/request:

        What I'd love to do is appending a link to a node giving the comparable portable (or windows) version of $ENV{f}="a b; 'c'"; system q{dir "\$f"}.

        Alternately at most a single concise paragraph as a footnote on the windows side of things to Re: *SAFE* use of string in system command.

        Otherwise its a bit unfair if the Unix view hogs all the good keywords and doesn't help a windows SoPW :)


        What I currently have - after some searching on PerlMonks - is a mess and a headache (and a bit of glee in lacking the windows environment to test this mess).

        It reads like system/exec/(pipe-)open should be avoided on Windows for non-trivial commands, preferring IPC::System::Simple or Win32::Process::Create instead.

        Do we have a better explanation or tutorial already on PerlMonks or do you know of a suitable resource outside?
        Merci!

        cu & thanx, Peter -- hints may be untested unless stated otherwise; use with caution & understanding.
      $ENV{PWD} is not portable
      use File::chdir; $CWD = "/foo/bar"; # now in /foo/bar { local $CWD = "/moo/baz"; # now in /moo/baz ... } # still in /foo/bar!
Re: running programs from PERL
by Anonymous Monk on Oct 25, 2009 at 08:36 UTC
Re: running programs from PERL
by CountZero (Bishop) on Oct 25, 2009 at 08:37 UTC
    On what OS are you?

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      im using cent OS