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

Here is the parameter string I want to feed to an old PERL script that I used to run through CGI:

?a_SEARCH_VALUE=^.{44}15&searchfields=all&sensecase=nocase&sorttype=none&datetype=comp&numorname=authnames

My latest of many efforts is the command line:

perl bl.pl <input.txt >output.html

where input.txt just contains that string. For most of my experiments, the resulting HTML file is correct for the case with no input, which is tested in the code.

I clearly don't understand how CGI passes the input parameter string to the PERL interpreter (in a Linux shell), but the best lead here was an old post about this website:

http://stein.cshl.org/WWW/software/CGI/cgi_docs.html

Unfortunately, that website only times out now... I think there is a quick and easy solution, but my chief sin is a lack of hubris?

Can't remember all my other experiments, but another obvious one also failed:

perl bl.pl >output.html "?a_SEARCH_VALUE=^.{44}15&searchfields=all&sensecase=nocase&sorttype= +none&datetype=comp&numorname=authnames"

Replies are listed 'Best First'.
Re: Running a CGI script from a command line?
by Your Mother (Archbishop) on Jun 15, 2015 at 06:07 UTC

    Seems to be just a shell arg issue + you don’t need the “?” Try this–

    perl bl.pl "a_SEARCH_VALUE=^.{44}15&etc=etc" > output.html
Re: Running a CGI script from a command line?
by kcott (Archbishop) on Jun 15, 2015 at 07:14 UTC

    G'day shanen,

    Welcome to the Monastery.

    The documentation for the CGI module is now on CPAN.

    The section that's probably most pertinent is DEBUGGING, which starts

    "If you are running the script from the command line ..."

    which pretty much paraphrases your original question.

    -- Ken

Re: Running a CGI script from a command line?
by afoken (Chancellor) on Jun 16, 2015 at 07:38 UTC

    All other postings assume that the old script uses the CGI module, which has some debugging features. But there also is a generic way to fake CGI context from a shell, that works for all CGIs, written in any language. The trick is to know how CGI works, this is documented in RFC 3875.

    Short summary: CGI programs are invoked with STDIN connected to a file or pipe delivering POSTed content, STDOUT connected to a file or pipe collecting output for the browser, STDERR connected to a file or pipe for logging. This is nearly the same setup you would expect from any unix command line utility. The big difference are arguments, they are passed via the environment, not as program parameters.

    For a GET or HEAD request, you can ignore STDIN. If you are paranoid, redirect from /dev/null. For a POST request, you need to write the POSTed data into STDIN of the CGI program in the same format that the browser would send it to the webserver. You also have to set the environment variable "CONTENT_LENGTH" to the number of bytes in the POSTed data.

    In any case, you should set the enviroment variable "GATEWAY_INTERFACE" to "CGI/1.1", as several CGIs use this to tell the difference between running in CGI mode (variable set) and running from command line for debugging (variable not set). The request method ("GET" / "HEAD" / "POST") is stored in "REQUEST_METHOD". CGI parameters that would be encoded in the URL have to be stored in the environment variable "QUERY_STRING", excluding the "?". Extra path elements in the URL, following the script URL, have to be placed in the environment variable "PATH_INFO".

    Some rare CGIs need to know more, e.g. the host name from the URL ("HTTP_HOST"), the document root directory ("DOCUMENT_ROOT").

    To fake a GET request for http://www.example.com/cgi-bin/some.cgi/extra/path/elements?name1=value1&name2=value2, minimally do this:

    /usr/bin/env GATEWAY_INTERFACE='CGI/1.1' REQUEST_METHOD='GET' PATH_INF +O='/extra/path/elements' QUERY_STRING='name1=value1&name2=value2' /sr +v/www/cgi-bin/some.cgi

    Note that you need to quote the ampersand (&), as it has a special meaning for most shells. To avoid shell traps, simply put every value in single quotes. Also note that all data from the URL stays URL-encoded (i.e. with %), decoding the values is done by the CGI.

    Of course, you can put that in a shell script, that makes it easier to call the CGI program:

    #!/bin/bash export GATEWAY_INTERFACE='CGI/1.1' export REQUEST_METHOD='GET' export PATH_INFO='/extra/path/elements' export QUERY_STRING='name1=value1&name2=value2' exec /srv/www/cgi-bin/some.cgi

    You could also use a Perl script instead of bash, e.g. to set the encoded QUERY_STRING environment variable from unencoded command line arguments instead of hard-coding it:

    #!/usr/bin/perl # called as wrapper.pl name1 arg1 name2 arg2 ... use strict; use warnings; sub encode { my $value=shift; $value=~s/([^A-Za-z0-9._-])/sprintf('%%%02X',ord $1)/ge; return $value; } $ENV{'GATEWAY_INTERFACE'}='CGI/1.1'; $ENV{'REQUEST_METHOD'}='GET'; $ENV{'PATH_INFO'}='/extra/path/elements'; my @pairs; while (@ARGV) { my $name=encode(shift @ARGV); my $value=encode(shift @ARGV); push @pairs,"$name=$value"; } $ENV{'QUERY_STRING'}=join('&',@pairs); exec('/srv/www/cgi-bin/some.cgi') or die "exec failed: $!";

    I'm sure there is a way to do that in bash, too. But this is perlmonks, not bashmonks. ;-)

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      The CGI.pm test suite does a lot of that, there is even a different helper to do that HTTP::Request::AsCGI - Set up a CGI environment from an HTTP::Request

      Extremely informative reply, though I have yet to digest all of it. This is a partial ACK, though my first experiments using this information produced strange results. Perhaps I have managed to confuse my environment a bit, but I'll switch to a fresh machine tonight and try again.

      My hope is high. Also, I'm reminded by your sit to add mine (though probably in the wrong way).

      --

      Freedom = (Meaningful - Coerced) Choice ≠ (Beer | Speech)

      Okay, finally some progress to report, though I mostly feel increasingly ignorant in spite of the expert guidance. I can make it work by inserting the "QUERY_STRING" (without the leading "&" into the subroutine that appears below... In other words, the problem seems to be that there is nothing I can figure out that will get the parameter string into the QUERY_STRING part of the environment.

      This mostly captures my past experiences with PERL... Enlightenment eludes me.

      In particular, I cannot understand why the explicit command line assignment to QUERY_STRING fails. That is both the assignment in a PERL command line and the assignment with the shell set command. "These are not the ENV variables you are searching for..."

      Right now I feel like rewriting the entire thing in Python. Is that sacrilegious, or just practical?

      sub html_parse { local($line, $length, $offset, @pairs); # Just use a GET and the one line? $line = $ENV{"QUERY_STRING"};
      Freedom = (Meaningful - Coerced) Choice ≠ (Beer | Speech)

        OK, time for a SSCCE. See if you can follow this simple illustration. If not, please reply and explain explicitly which bit you cannot reproduce or do not understand.

        bash-$ cat my.cgi #!/usr/bin/perl use strict; use warnings; use CGI::Lite (); my $cgi = CGI::Lite->new; $cgi->parse_form_data; print "Content-type: text/plain\n\n"; $cgi->print_form_data; bash-$ export REQUEST_METHOD=GET bash-$ export QUERY_STRING='foo=bar&baz=quux' bash-$ ./my.cgi Content-type: text/plain foo = bar baz = quux

        In this example I have shown you the trivial CGI code, demonstrated how to set the two key environment variables from within the shell (any Bourne-like shell will use this syntax) and then run the script from within the same shell process to show that it has processed the supplied query string.

        Note, I've used CGI::Lite here for brevity but any of the CGI modules from CPAN should work in a similar fashion as explained by afoken above.

        Update: Amended $PS1 for even more clarity, just in case.

Re: Running a CGI script from a command line?
by Anonymous Monk on Jun 16, 2015 at 03:23 UTC

      A fun approach; maybe overkill here. It’s multi-arg system that avoids the shell, not capture.

        Unsure of protocol, but this is just a first ACK. The 1st reply was included in my early experiments, but I tested it again. The 3rd reply looks promising, but I'm working from the 2nd reply now... My ignorance remains profound, but I suspect I can clap the third hand.

        A fun approach; maybe overkill here. It’s multi-arg system that avoids the shell, not capture.

        Well sure :) but if you don't capture it, it just goes into the regular place, at which point, the question becomes, why not do a redirect instead?

        Oh right, the OP didn't ask that exactly, that was just the question that brought me to this question (from a cgi execute another cgi) ... looked close enough :)