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

Hi, I'm trying write a script that will call a unix comand and either post the results or parse the results then post them. I thought perhaps I could accomplish this with exec or system. However, I haven't been able to figure it out. Any insight would be much appreciated. Thanx

Replies are listed 'Best First'.
Re: calling Unix commands
by cwest (Friar) on Oct 18, 2000 at 20:53 UTC
    You can use backtics ( `ls` ) to return the output of a command, or you could use the Shell module.
    use Shell; print ls();
    And if you have a development version of Perl laying around ( 5.7.0 :) you can check out the OO interface to Shell ( you're welcome :)
    use Shell; my $sh = shell->new; print $sh->ls;
    Bad namespace polution, bad!
    --
    Casey
       I am a superhero.
    
Safer system(), exec(), and `` (was RE: calling Unix commands)
by DrManhattan (Chaplain) on Oct 18, 2000 at 22:42 UTC
    Be very careful executing commands if you're going to accept input from untrusted sources. If you feed system(), exec(), or backticks a scalar (non-array) argument, it goes to the system shell for interpretation. For instance, let's say you're trying to allow users to specify a file to run "ls -l" on:
    # Instead of passing a file name, a malicious user sends # another command $user_input = "; rm -rf /"; # system() happily executes "ls -l" followed by "rm -rf /" system("ls -l $user_input");
    To avoid this, you should always pass array arguments to system() and exec():
    $user_input = "; rm -rf /"; # In this case the user just gets a "no such file or # directory" error system("ls", "-l", $user_input);
    Backticks are a bit trickier because there's no syntax to pass in an array argument. To safely capture the output of a command, use open() to fork off a child and exec() to execute the command:
    # Bad @output = `ls -l $user_input`; # Good if ($kidpid = open(PIPE, "-|")) { # Parent process. Read data from the child. @output = <PIPE>; } else { # Child process. Execute the command. die "could not fork" if !defined($kidpid); exec ("ls", "-l", $user_input) or die "exec failed: $!"; }

    -Matt

Re: calling Unix commands
by Fastolfe (Vicar) on Oct 18, 2000 at 21:24 UTC
    Not sure why you're having trouble with system and exec, but these are the typical 'norm' with respects to calling external programs.
    system("/bin/ls", "-la", "/home"); system("/bin/ls -la /home"); # less efficient exec("/usr/bin/some-other-program", "argument");
    See the documentation for system and exec. As far as the rest of your question, with respects to parsing and posting whatever these "results" are, you're going to need to give us more information. If you're wanting to send data to/from the application you're going to be calling, you will need to use the process form of open, and/or set up some pipes and perhaps fork/exec, or even use something like open2/open3. See perlipc for information about inter-process communication, if that's what you're going for.

    You may also want to check out How do I run another program from within my Perl program?, in the Categorized Q&A section.

    We could really use more information if this doesn't answer your question.

Re: calling Unix commands
by wardk (Deacon) on Oct 18, 2000 at 21:26 UTC

    Max_Glink,

    Coincidentally I just came across some code on a new project that speak to the issue of "what method to use to execute a unix command".

    The code needed to get the output from an in-house employee lookup program and return some of the values to an HTML page.

    The method being used was using "system" and piping the command output to a tempfile, then opening the tempfile and getting the data back out for display. Although functional, it was not especially efficient.

    My alternative was to use "backticks" for the command, which allowed me to capture the output to an array, which I then passed to the parser than was managing the array created by the file read.

    Here are the two methods.

    # assume $lname, $tempfile were assigned previously my $command = "unix_blues -w $lname >> $tempfile"; my $rc = system($command); # the above puts the output into $tempfile and the return code in $rc # they then open, read the tempfile putting lines into array (which co +uld have # also been done in one line)

    One problem with the above was that for whatever reason, they occasionally had tempfiles lying around from failed unlinks.

    So I changed it to this, which resolved the tempfile issue and removed the file I/O

    my $command = "unix_blues -w $lname"; @BluesData = `$command`;

    the above put the output lines into @BluesData which I then passed to an existing routine that parsed it.

    It sped things up considerably.

    Just more proof TIMTOWTDI!

    Good luck!