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

Greetings,

I'm having this problem that's driving me nuts and I'm hoping one of the monks here has dealt with, solved it, and is willing to share.

First, a little background:
I'm on a P4 2.2gHz Windows XP machine (with all the latest patches) with lots of RAM, a very large harddrive using ActivePerl Build 804, trying to code a cross platform package.

My problem is that I have a situation where I need to pass a very long argument string to an external program (a java program actually), which could be well over the 357 charecter limit I have seen mentioned here. When I try to do this, I don't get an error, instead the perl binary crashes on me...

I have tried implementing the code mentioned in http://www.perlmonks.com/index.pl?node_id=151886 and an other node mentioned here (sorry I forgot which one), and both give the same results. A perl crash....

Please help. This has been driving me nuts for the last few days and I don't know what else to do...

  • Comment on Passing a very long parameter list to an external command in perl

Replies are listed 'Best First'.
Re: Passing a very long parameter list to an external command in perl
by bbfu (Curate) on Oct 23, 2003 at 23:04 UTC

    Keep in mind that (from perldoc -f system):

    ... If there is only
    one scalar argument, the argument is checked for shell
    metacharacters, and if there are any, the entire argument is
    passed to the system's command shell for parsing

    So, you may want to make sure you don't use any shell metacharacters, and/or that you use the LIST form of system, as your particular shell might be limiting the command-line (or causing other problems).

    bbfu
    Black flowers blossom
    Fearless on my breath

Re: Passing a very long parameter list to an external command in perl
by BrowserUk (Patriarch) on Oct 23, 2003 at 22:33 UTC

    I think you need to explain a little more about how you are invoking the external command and passing the parameter list?

    I'm able to pass comand lines of upto 32767 characters using system running AS under NT, and I doubt that XP has reduced this capacity, so I assume that you are using some other way of spawning the external comand and are running up against it's limitations rather than the OS per se.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

Re: Passing a very long parameter list to an external command in perl
by dwhitney (Beadle) on Oct 23, 2003 at 23:04 UTC

    OK, I've been asked to provide a bit more detail and provide a code sample. The external program is the command line interface to the Responsys Interact system

    In my script, I have a call that goes like:
    my $editcampaign = $cliObj->editcampaign( campaign => "Fake_Test_Campaign", folder => "Big_Fake_Directory_For_testing_only", dist => "Big_Fake_Directory_For_testing_only test_data_source", html => "Big_Fake_Directory_For_testing_only fake_file.htm", aol => "Big_Fake_Directory_For_testing_only fake_file.aol", text => "Big_Fake_Directory_For_testing_only fake_file.txt", autosense => 1, );

    Then with in the package I'm building, I'm generating the command string with:

    sub editcampaign { my $self = shift; my( $data, $ret ); ( @_ ) ? ( %$data ) = @_ : return; return if ( ( !$data->{'campaign'} ) or ( scalar( keys %$data ) < +1 ) ) ; push @$ret, qq|-locale $data->{'locale'}| if ( $data->{'locale' +} ); push @$ret, qq|-folder $data->{'folder'}| if ( $data->{'folder' +} ); push @$ret, qq|-ackurl $data->{'ackurl'}| if ( $data->{'ackurl' +} ); push @$ret, qq|-followup $data->{'followup'}| if ( $data->{'fol +lowup'} ); push @$ret, qq|-test $data->{'test'}| if ( $data->{'test'} +); push @$ret, qq|-optout $data->{'optout'}| if ( $data->{'optout' +} ); push @$ret, qq|-dist $data->{'dist'}| if ( ( $data->{'dist' +} ) and ( $data->{'dist'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-html $data->{'html'}| if ( ( $data->{'html' +} ) and ( $data->{'html'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-text $data->{'text'}| if ( ( $data->{'text' +} ) and ( $data->{'text'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-aol $data->{'aol'}| if ( ( $data->{'aol'} ) + and ( $data->{'aol'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-attach $data->{'attach'}| if ( ( $data->{'attac +h'} ) and ( $data->{'attach'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-sentlog $data->{'sentlog'}| if ( ( $data->{'sen +tlog'} ) and ( $data->{'sentlog'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-ackdoc $data->{'ackdoc'}| if ( ( $data->{'ackdo +c'} ) and ( $data->{'ackdoc'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-responsedb $data->{'responsedb'}| if ( ( $data- +>{'responsedb'} ) and ( $data->{'responsedb'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-failedlog $data->{'failedlog'}| if ( ( $data->{ +'failedlog'} ) and ( $data->{'failedlog'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-clicktrack $data->{'clicktrack'}| if ( ( $data- +>{'clicktrack'} ) and ( $data->{'clicktrack'} =~ /(.*) (.*)/ ) ); push @$ret, qq|-clickthru $data->{'clickthru'}| if ( ( $data->{ +'clickthru'} ) and ( $data->{'clickthru'} =~ /(.*) (.*) (.*) (.*)/ ) +); push @$ret, qq|-skipdup ON| if ( $data->{'locale'} ); push @$ret, qq|-autosense ON| if ( $data->{'autosense'} ); push @$ret, qq|-opensense ON| if ( $data->{'opensense'} ); push @$ret, qq|-useaccountwide ON| if ( $data->{'useaccountwide +'} ); push @$ret, qq|-conversiontrack ON| if ( $data->{'conversiontra +ck'} ); push @$ret, qq|-htmltoaol ON| if ( $data->{'htmltoaol'} ); push @$ret, qq|-autosenseaol ON| if ( ( $data->{'autosenseaol'} + ) and ( ( $data->{'autosense'} ) or ( $data->{'opensense'} ) ) ) ; push @$ret, $data->{'campaign'}; $ret = join " ", @$ret; # Log action $self->{'LOGGER'}->log( level => 'notice', message => "campaign $r +et\n" ); #execute it ( $ret ) = $self->executeCommand( "campaign $ret" ); return 1; }

    The executeCommand call is the code provided in http://www.perlmonks.com/index.pl?node_id=151886 with a few minor tweeks made for logging and returning the results set.

    Interesting side note: when I try this from the command line, I get a return saying:
    Warning!!! Turning skip multipart OFF since auto-sense is used.
    and the command still executes, setting all of the things I care about.

    Any thoughts?

    P.S. I will also gladly accept any style hints/pointers involved with creating the command line string.

      There is no executeCommand() sub in Re: IPC::Open3 woes? (I checked 3 times:)


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      Hooray!

      How are you executing the command? This is pretty important. If you can use system with a list of arguments instead of a single string. From your code, you are likely using the single argument form of system which has all the quoting and length limits of the shell.
      $ret = join " ", @$ret; #execute it ( $ret ) = $self->executeCommand( "campaign $ret" )
      Since you already have the list of arguments, you can use that. You will have to use the array form of system. If you need to read the stdout of the program, I think that IPC::Open3 supports an array of arguments.
      system('campaign', @$ret);

        After finally getting it through my thick skull, I skipped the whole $ret = join " ", @$ret; and now simply pass the array to the sub.

        It works vewry well thank you!!

        Thanks for finally doing it jburrel!!!