Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Array for system() call

by proxima (Acolyte)
on Oct 23, 2001 at 16:46 UTC ( [id://120765]=perlquestion: print w/replies, xml ) Need Help??

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

Can someone explain to me the difference between the following two fragments of code, and why one works differently to the other: First fragment:
@Call[0] = "gawk -f test.gawk test.file > out.file"; system(@Call);
Second fragment:
@Call[0] = "gawk"; @Call[1] = "-f"; @Call[2] = "test.gawk"; @Call[3] = "test.file"; @Call[4] = ">"; @Call[5] = "out.file"; system(@Call);
The first example works as planned - the second example runs the gawk script, but doesn't redirect the output. I've tried other variations, none of which work. Can anyone help me understand how to implement a redirection like in the second example? Thanks.

Replies are listed 'Best First'.
Re: Array for system() call
by MZSanford (Curate) on Oct 23, 2001 at 16:53 UTC
    When system() gets a scalar, it goes to the shell to execute the command. This means that you open a new shell instance (such a ksh), and run the program, including any redirection.

    If system() gets an array, it instead does the fork() and then uses exec() to start the process. This by-passes the shell, so shell redirection does not work.
    i had a memory leak once, and it ruined my favorite shirt.

      To elaborate further, use this (note double quotes): system("@Call"); instead of this: system(@Call); to achieve the same effect as your first fragment.

      And, BTW, you probably meant to do this:

      $Call[0] = "gawk"; $Call[1] = "-f"; $Call[2] = "test.gawk"; $Call[3] = "test.file"; $Call[4] = ">"; $Call[5] = "out.file";

      or (slightly more efficiently) this:

      @Call = ( "gawk", "-f", "test.gawk", "test.file", ">", "out.file" );

      rather than your original code, which is assigning values to 1-element array slices, which are sublists -- NOT arrays! -- of references to the elements of the @Call array; needless to say, although it works, it is somewhat less efficient than either of the above approaches, and bad practice besides.

      dmm

      Give a man a fish and you feed him for a day ...
      Teach the man to fish and you feed him for a lifetime
      
        Here is an example of why using @arr[0] is just asking from trouble...
        #!/usr/bin/perl -wT use strict; my @arr; @arr[0] = localtime(); $arr[1] = localtime(); print "\$arr[0] = $arr[0]\n"; print "\$arr[1] = $arr[1]\n";
        Any guesses about the output of this simple script? Select area below to find out.

        =OUTPUT Scalar value @arr[0] better written as $arr[0] at ./arrayslice.pl line + 6. $arr[0] = 58 $arr[1] = Tue Oct 23 14:30:58 2001
        5 points for anyone who expected $arr[0] to contain an integer. 20 points for anyone who knew it would contain the seconds value, *not* the number of elements in the list returned by localtime().

        (10 points for anyone who coded up an example because they weren't sure... woohoo)

        -Blake

Re: Array for system() call
by broquaint (Abbot) on Oct 23, 2001 at 16:53 UTC
    Firstly, you're using array slices for your assignment, which I believe is not what you want, but I digress.
    The first method works because the string that system gets is passed to a shell (usually something like `sh -c $str`) so it executes it as you might expect.
    The second method doesn't work because what happens is that system takes the first element in the array as the program to execute, and the remaining elements as arguments to be passed to that program. So the reason it won't work is that gawk is also taking '>' and 'out.file' as arguments, when you really want the shell to interpret them.
    HTH

    broquaint

    P.S If you're stuck with [mgn]awk scripts you might want to take to them with a2p which comes with the standard perl distro.

Re: Array for system() call
by snafu (Chaplain) on Oct 23, 2001 at 19:03 UTC
    change system(@Call) to system("@Call"); and it will work.

    [jconner@kwan ~]$ perl -e ' @Call[0] = "gawk"; @Call[1] = "-f"; @Call[2] = "test.gawk"; @Call[3] = "test.file"; @Call[4] = ">"; @Call[5] = "out.file"; print "system(@Call)\n";'

    prints: system(gawk -f test.gawk test.file > out.file)
    which wouldn't even work if you literally placed it that way in a script. However, If you ran this: system("gawk -f test.gawk test.file > out.file") in a script that would work. So, therefore, enclose your array in the system() call in quotes. It works. :)

    [jconner@kwan ~]$ ls -l out.file gls: out.file: No such file or directory [jconner@kwan ~]$ perl -e ' @Call[0] = "ls"; @Call[1] = "-al"; @Call[4] = ">"; @Call[5] = "out.file"; system("@Call");' [jconner@kwan ~]$ ls -l out.file -rw-r----- 1 jconner other 4637 Oct 23 10:56 out.file [jconner@kwan ~]$

    ----------
    - Jim

Re: Array for system() call
by pike (Monk) on Oct 23, 2001 at 19:08 UTC
    Not directly answering your question, but you can get the effect of redirection using pipes (supposing you read in the contents of out.file somewhere later in your program). Works like this:

    $Call = 'gawk -f test.gawk test.file'; open (CMD, "$Call |") or die "Error in command $Call: $!\n"; while (<CMD>) { #process output records }

    pike

Re: Array for system() call
by thunders (Priest) on Oct 23, 2001 at 19:19 UTC
    I think this will work for you. Simply make the list a string.
    $command = join(" ", @Call); system($command);
Re: Array for system() call
by Ven'Tatsu (Deacon) on Oct 24, 2001 at 03:17 UTC
    Read system. (which points to exec for more info) it says that if system has more than one argument, an array with more than one item, or the lone item does not have shell metacharacters it will not use a system shell, that means chracters like '>' are not processed but are passed as arguments.
    Not using a shell is safer and faster.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://120765]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (5)
As of 2024-04-25 14:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found