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

Redirection with Win9x batch files

by footpad (Abbot)
on Dec 09, 2000 at 00:12 UTC ( #45781=perlquestion: print w/replies, xml ) Need Help??

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

Momentarily setting aside any discussion of the merits of various operating systems, the apprentice requests feedback from the community regarding the following:

First off, I apologize for the length of the post. It's involved, but I've tried to be as brief as possible and I'd appreciate any feedback on a solution designed to make it easier to develop Perl scripts on my Windows machines. The additional detail is designed to help fill the gaps when necessary, as well as demonstrate that I've tried to do my homework.

Like many of you, I prefer to debug my Perl scripts locally before uploading them to my server; since the bulk of my development work involves Windows, that means installing ActivePerl and configuring my Win9x development machine appropriately.

If you have a more than passing familiarity with MS-DOS and the limitations of batch files, you know that a long PATH statement is less than ideal, especially if you have a number of software programs that require PATH entries (local database servers, 16-bit programs, certain application development command-line tools, various utilities, and so on).

Over the years, I've gotten into the habit of using batch files to call various things on my system. By collecting these into a single directory, I've been able to keep my PATH small and reserve environment space for other uses.

My first batch file for Perl looked like this:

@echo off c:\devt\perl\bin\perl.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 echo on

This worked well, until I started trying to debug scripts that returned more than 25, 43, or 50 lines of output (corresponding to the sizes you can set your MS-DOS prompt to support). In *nix, you can redirect output to files or pipe it to display utilities very easily. This also works in DOS, but only if you call perl.exe directly (for batch files do not let you pass redirection or piping commands as parameters to programs in your batch files.)

For example, you can't use something like:

perlbat -V > stdout.log

because the perlbat file assumes that it's supposed to handle this and doesn't pass that information to the program(s) called within the batch file.

Because of the way I've configured my system, this means I need to type:

c:\devt\perl\bin\perl -V > stdout.log

to redirect the output. While I could type the extra seventeen characters when needed, this seemed like too much work. (laziness, impatience, etc). After getting some hints via CB a couple of days ago (thanks, Tilly) and reviewing relevant nodes found with Search (thanks to the posters), my perl.bat now looks like this:

@echo off c:\devt\perl\bin\perl.exe -e "$so=qw(stdout.log); $se=$so; open STDOUT +, qw(>).$so; open STDERR, qw(>).$se; @args = qw(perl, %1, %2, %3, %4, + %5, %6, %7, %8, %9); system(@args) == 0 or warn qw(Failure: $?);" echo on

My petitions are:

  1. Understanding that this is for development and debugging convenience only (not deployment or CGI use), does anyone have any feedback, recommendations, or suggestions to offer?
  2. Have I unecessarily reinvented a wheel?
  3. Keeping the alternate solution (provided later) in mind, is there an easier way to do this?
  4. Would it be adviseable to unlink the log files before the system call? (On some level, it seems a stylistic choice. I'm trying to make sure that's all it is.)

For clarity, here's a formatted version of the code being executed:

$so = qw( stdout.log ); $se = $so; open STDOUT, qw( > ) . $so; open STDERR, qw( > ) . $se; @args = qw( perl, %1, %2, %3, %4, %5, %6, %7, %8, %9 ); system( @args ) == 0 or warn qw( Failure: $? );

Note: if you wish to adapt the above into an external script, line 5 in the above needs to be changed to something along these lines:

@args = qw( perl, @ARGV );

Other notes for those wishing to adapt this for their use:

  • To send STDERR to a different file, replace "$se = $so" with the name of the file you want to use. For example, "$se = qw( stderr.log );" appears to work well.

  • If the command cannot be executed, the log contains the DOS error message, as expected. In certain cases, however, this can lead to a bit of confusion. For example, I set @arg[0] to "perlxyz" to test a failure condition and then used TYPE to display the log. The response was "Bad command or file name." This caused momentary alarm until I used EDIT to look at the log. As soon as I did that, I realized that the computer did what I told it and that my interpretation of the results were incorrect. (D'oh!)

  • I used qw() throughout the code to make it easier to pass as a one-liner using -e.

  • I am aware that there is another way to do this. I chose this route because it a) seemed more perlish (use Perl to run itself), b) I wanted to solidify my basic skills, and c) this seemed the most flexible solution overall.

    In the spirit of TIMTOWTDI, an alternate solution follows:

The alternate approach

If the above approach doesn't appeal to you, here's an alternate batch file that works by "adding" a command-line option to your perl batch file to log STDOUT to a text file:

@echo off '----- ' plog.bat: Optional logging for perl on Win9x. ' ' To log STDOUT, add -L to the parameters. For example: ' ' c:\> plog -L ' ' redirects Perl's STDOUT to a file called stdout.log ' located in the current directory. Share and enjoy. if !%1! == !-L! goto log1 if !%2! == !-L! goto log2 if !%3! == !-L! goto log3 if !%4! == !-L! goto log4 if !%5! == !-L! goto log5 if !%6! == !-L! goto log6 if !%7! == !-L! goto log7 if !%8! == !-L! goto log8 if !%9! == !-L! goto log9 goto nolog :log1 set params=%2 %3 %4 %5 %6 %7 %8 %9 goto doit :log2 set params=%1 %3 %4 %5 %6 %7 %8 %9 goto doit :log3 set params=%1 %2 %4 %5 %6 %7 %8 %9 goto doit :log4 set params=%1 %2 %3 %5 %6 %7 %8 %9 goto doit :log5 set params=%1 %2 %3 %4 %6 %7 %8 %9 goto doit :log6 set params=%1 %2 %3 %4 %5 %7 %8 %9 goto doit :log7 set params=%1 %2 %3 %4 %5 %6 %8 %9 goto doit :log8 set params=%1 %2 %3 %4 %5 %6 %7 %9 goto doit :log9 set params=%1 %2 %3 %4 %5 %6 %7 %8 goto doit :nolog c:\devt\perl\bin\perl.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 goto ciao :doit c:\devt\perl\bin\perl.exe %params% > stdout.log set params= :ciao echo on

You'll not that while this lets you specify -L to log STDOUT, it doesn't log STDERR unless your script points STDERR to STDOUT using something along these lines:

open STDERR, ">&STDOUT";

(Credits and details here and here.)

Also, there's a risk associated with this approach because it's entirely possible that future versions of Perl may include a -L switch. You'd have to rewrite your batch file in that case.

For best results with either approach, you may find it helpful to use two batch files to run perl:

  • perl.bat runs the process without redirection.
  • plog.bat to log STDOUT (and possibly STDERR) to a text file.

By doing so, you can take advantage of DOS's limited command repetition support, e.g.

  1. type "perl" to run the script the first time and note the need to log results.
  2. type "plog", press F3, and then his Enter to reduce the keystrokes needed to log the previous results.

In the end, choose the approach that works best for you and be sure to take any wisdom attached in any replies into account.


Replies are listed 'Best First'.
Re: Redirection with Win9x batch files
by Blue (Hermit) on Dec 09, 2000 at 01:03 UTC
    footpad, I admit up front that I don't use MS-(DOS|Win3?) batch very oftern (I"m a Unix SA), but couldn't you simplify the task simply by having two batch scripts, one which called Perl, and one which called Perl and redirected the output.

    c:\devt\perl\bin\perl.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 > stdout.log No need for all the extra checking. Frankly, the batch processing isn't all that powerful. I look at the alternative example and cringe. (Not at you, but at the lack of power of the batch.)

    "Beware of false laziness" is the council in one of the zoo books. I think this may be a case of it. 8)

    BTW, thorough doing of your homework. Still a ++ for good forethought.

    =Blue might be eaten by a grue...

      Not to turn this into batchmonks, but you could also get rid of much of the redundancy in that big ol' batch file by using something like this (untested):

      :Loop REM If there are no parameters left, just go run perl if !%1! == !! goto doit REM If there's a -L, set the log flag if !%1! == !-L! set log=1 REM If this isn't a -L, push it on to the params stack if not !%1! == !-L! set params=%params% %1 REM Shift that %1 off and continue (%2 is now %1, etc) shift goto Loop :doit if !%log%! == !1! goto Log c:\devt\perl\bin\perl.exe %params% goto ciao :Log c:\devt\perl\bin\perl.exe %params% > stdout.log :ciao set params= set log= echo on

      Recursion is your friend!

        myocom: Excellent! (And I thought I had batch files cold.) ;-)

        Thanks for reminding me that there's always more to learn.

        Blue: Good point. Initially, I wanted to maintain a single batch file, if possible. After continued reflection, this looks like a case where two one-line batch files are easier to understand after the development fit. Any maintenance difficulties could be easily handled with documentation (comments in the batch files). (Which is a nice way of saying, it would help me remember what I was trying to accomplish when I looked at those files later.)

        Anyone have thoughts regarding the utility of unlinking the log files before the system call? Good idea? Bad idea? No matter?


Log In?

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

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (2)
As of 2021-01-24 02:38 GMT
Find Nodes?
    Voting Booth?