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

I'm trying to execute a series of perl scripts that are in a Batch file. I want an admin person to be able click a hyperlink in an HTML page and the act of clicking the hyperlink to run the batch file with the multiple perl scripts in it. To try and do this I've written a Perl script that can be called from a hyperlink in an HTML page. This is the piece of HTML:
<a href="runindex.pl">Re-write the Indexes</a> (note this can be run at any time of day)<br>
(The page loads up fine) This is the perl script 'runindex.pl':
use strict; my $program="index.bat"; #$status= system $program or die "$program exited funny: $?";
This 'runindex.pl' runs fine from the dos command line, but when I try and run the script by clicking on the hyperlink I get this error:
CGI Error The specified CGI application misbehaved by not returning a complete s +et of HTTP headers. The headers it did return are: The name specified is not recognized as an internal or external command, operable program or batch file.
I get the distinct feeling that I'm missing something obvious, but I've been looking for an answer all day and have come up with diddly squat. I've tried both exec and system but got no more results with either of them. I'm plumping for system as I don't need to send arguments or get results back. Any help would be greatly appreciated

Replies are listed 'Best First'.
Re: Am I missing something major here (system/exec)?
by izut (Chaplain) on May 23, 2006 at 16:08 UTC

    You must print the HTTP headers!

    use strict; use warnings; use CGI::Carp qw(fatalsToBrowser); my $program = "C:\full\path\to\index.bat"; # unless it's in the same d +irectory. print "Content-type: text/html\n\n"; # this is the header the browser +expects. system $program == 0 or die "$program exited funny: $!";

    Update: Updated comments.

    Update: Updated system usage, as japhy said.

    Update: As ww pointed, you have to return something to browser, even a simple html document saying everything's ok, or a simple redirect to another web page. If you don't, the browser will always complain about that.

    Igor 'izut' Sutton
    your code, your rules.

Re: Am I missing something major here (system/exec)?
by japhy (Canon) on May 23, 2006 at 16:18 UTC
    What izut said, except that system() returns 0 on success, not failure.
    system(...) == 0 or die "..."; # or system(...) and die "...";

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Am I missing something major here (system/exec)?
by ptum (Priest) on May 23, 2006 at 16:49 UTC

    It is not immediately obvious to me under which operating system you are running, but a word of caution seems in order. On Unix systems running Apache (for example), the userid under which CGI scripts run (often 'nobody' or 'webuser') is distinct from other more privileged userids and may not have the permissions to execute your batch scripts or open certain files. Also, the environment under which a webuser runs may be quite distinct (in terms of path and other variables) from a command-line user unless you explicitly set that environment. Whenever I hear someone say "It ran fine from the command line but not from the browser" I think of these two common problem areas.

    The 'print header' and fatalsToBrowser answers you have received should help you identify any further problem that you may have.


    No good deed goes unpunished. -- (attributed to) Oscar Wilde
      Thanks folks - I knew it had to be something simple, but sadly it hasn't totally sorted it.

      I'm running on a Windows NT server. Where I have the HTML and perl is the normal location for this type of stuff and other scripts there run fine (from both form and hyperlink clicking).

      I've now changed the 'runindex.pl' script to this:

      #!/usr/local/bin/perl -w use strict; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; print "Content-Type:text/html\n"; print "\n"; print "<HTML>\n"; print "<Head></Head>"; print "<body>"; my $program="index.bat"; #$status= system ($program) ==0 or die "$program exited funny: $?"; print "</body>"; print "</HTML>";
      I can't 'use warnings' it's not in my Perl installation.

      I'm getting this error now

      Content-type: text/html Software error: index.bat exited funny: 256 at E:\Perlcgi\pipeline\runindex.pl line 14 +.
      and 'index.bat' isn't running (because the scripts it should run aren't updating the files they should update!).

      I can still execute 'runindex.pl' from the dos command line on the server though, so I'm dead confused.

      I've tried changing the HTML so that the script runs from a form submission, but I get exactly the same results.

      Would it be easier for me to execute the perl scripts that index.bat is trying to run, within 'runindex.pl'? (Like I know how to do that - not!) This is what index.bat does:

      todayindex.pl agentview2.pl serviceview1.pl salesview1.pl maview1.pl hoview1.pl caview1.pl bmview1.pl allindex.pl beneview1.pl charityview1.pl facview1.pl insuranceview1.pl mortview1.pl regulationview1.pl salesadvview1.pl savview1.pl systemsview1.pl trainview1.pl previndex.pl
      i.e runs a whole bunch of other perl scripts! Any more ideas? I've looked up the error code - it apparenlty can't fork the subprocesses. Why would that be?
        1. search/google for Windows && fork and you'll discover that there are some serious limitations there (and a wiser head, more familiar with NT may be able to tell you if its limitations are even more severe than those of consumer-oriented W32 OSen.

        2. Yes, of course you can execute those from your script, directly, but you may have to do so SEQUENTIALLY if your diagnosis of a fork-problem is correct. Would sequential execution be a problem?

        OTOH, I don't believe a Windows batch file does any forking. That would mean that the .bat is already trying to run your scripts sequentially, which, in turn, tends to throw the diagnosis into question.

        So, please take a look at:

        013: #$status= 014: system ($program) ==0 or die "$program exited funny: $?";

        ...and explain -- in detail -- to yourself, your teddybear and the Monks (if still need-be) what you think you're doing with those lines, noting that your script is now returning YOUR 'die' message, not something else.

        Possible HINT Did the scripts enumerated in your .bat run or not?
Re: Am I missing something major here (system/exec)?
by ww (Archbishop) on May 23, 2006 at 16:20 UTC

    While the error message(s) seems FAIRLY obvious... it is perhaps misleading. The fact that your .html page loads despite inoperable links is not terribly relevant. But the inoperable links are!

    To my eyes, your problem is trying to execute a script from an <a href...

    Customarily, one would use a form whose action = the file you wish to execute. Since it you're running on a windows server (1. sorry, no knowledge there; 2. It would be helpful to tell us, explicitly, rather than require us to draw inferences from your error!!), you may be able to make the .bat file the action, directly, but if not fall back on your (misleadingly named) "runindex.pl" in a valid .html form.

    You may wish to note that TTBOMK, ISPs and sysadmin rarely use the directory containing publicly available .html as a directory in which a (update specifying perl, in light of .php, etc) perl script is executeable. That may also have something to do with your error... Customarily, scripts go into a cgi-bin directory (location determined by the sysadmin or ISP)

    ...and, overall, the bits of information and code you've provided are not -- at least for me -- adquate to diagnose your problem. Please, Update with additional code, system info, etc.

      To my eyes, your problem is trying to execute a script from an a href...

      Really? Because that's the exact method you and every other perlmonk reader used to get to this thread, and is in fact the underpinning of most dynamic content on the Web today.

Re: Am I missing something major here (system/exec)?
by lukeyboy1 (Beadle) on May 23, 2006 at 16:19 UTC
    Someone may have beaten me to this one, but a simple addition of a content type should sort it out. e.g.
    use strict; print "Content-type: text/html\n\n"; my $program="index.bat"; #$status= system $program or die "$program exited funny: $?";
    This is likely to be because the webserver needs to know what kind of content it's dealing with. See content-type for more info......
Re: Am I missing something major here (system/exec)?
by roboticus (Chancellor) on May 25, 2006 at 10:54 UTC
    kjg:

    Since others are helping you on the Web/CGI/HTML front, I'm going to suggest a different tack: You might want to have a scheduled job that runs your batch jobs for you, and make your web interface simply trigger them. The method I use is having my scheduled job simply look for the presence of files in a particular directory. When it sees one, it executes the appropriate script with the trigger file passed in as the argument. (This way your Web app can send in any configuration values to the script--such as the EMail address to send the report to)

    This way, you can avoid some of the potential security problems mentioned by ptum and the forking problem mentioned by ww. My favorite reasons for this method, however, are:

  • You don't have to tie up an http thread while your script runs.
  • Other programs can easily trigger the same jobs.
  • Easy to test!
  • A single point of control for all batch jobs. Turn off your batch job, and nothing gets processed until you restart it! (Very nice if you're trying to do some maintenance, and don't want database records changing or getting locked under you.)

    Your scheduled job can be as simple as:

    REM DOIT.BAT REM REM Note: the .pl scripts are expected to delete their command file D: cd \WORK\QUEUE :LOOP sleep 60 if exists PAUSE_JOB goto LOOP for %%J in (NME\*) do NME_Rpt.pl %%J for %%J in (PURGE\*) do Purge_Old_Files.pl %%J goto LOOP
    Note: I'm typing in the batch file from memory, so consider it untested (and likely incorrect in some details)!

    --roboticus