http://www.perlmonks.org?node_id=1011174

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

Hi Folks,

I'm on a PC running Windows 7 and I am using ActivePerl. Once I work out the bugs the script this sub lives in will run on a Windows Server 2008 SP1 machine. Not sure which of that info might be needed/helpful, but there it is!

I have read about the ENV module, but I don't think it does what I need it to. I don't want the env variables in existence when the script is first run, I would like that errorlevel env var that is set (hopefully) when the script I call from inside my Perl script is run. To that end, I have a couple of questions.

1. If I call another script (a BeyondCompare3 script in this case) with a system call in backticks from a Perl script, is the DOS errorlevel environment variable set? I believe that's what I understand from all the reading I've been doing on it, but I wondered if anyone could confirm that.

2. If it is set, is my $errorLevel = %ERRORLEVEL; the proper way to access that value in my Perl script?

This is what my mock-up sub looks like so far:

sub FoldersIdentical(){ my $identical = 1; ($firstFile, $secondFile) = @_; `\"$BComp\" /closescript \@\"cacheCompareScript2.txt\" \"$firstFil +e\" \"$secondFile\"`; my $errorLevel = %ERRORLEVEL; print " \n\$errorLevel is $errorLevel\n"; if ($errorLevel == 0){ $identical = 0; } return identical; }

I know it's pretty obvious from looking at it, but the goal is to verify that the contents of the two folders are identical. Not so obvious probably is that nothing else needs to match - date modified, permissions, etc - only the contents of the folders need to be identical. I've run my script a few times, but I don't think I'm getting what I am looking for. For example, the installers in the deliveries and caching folder don't match today and here is the result I get in the console window when I run my Perl script $errorLevel is 0I know that the errorlevel is being set in response to that command running because when I intentionally mess up a folder name I do get a different code.

I've put a lot of work into this at this point so I'd like to make it work and would really like advice to that end, but I am also open to hearing about Perlish way to accomplish this folder comparison. It has to be heavy duty though because these folders are huge.

Thank you in advance for any advice. So grateful to have you all to ask.

Jennie

Update

I realize I didn't make it clear that I have looked up Perlish way to accomplish this and found this link at StackOverflow, but you need to download modules to make it work and I wasn't sure how safe that was. I'm on my work computer and so I can't be cavalier about naughty things getting in. Sorry if the StackOverflow reference is taboo. Just didn't want you all to think I came expecting you to do all the work for me.

Replies are listed 'Best First'.
Re: accessing an environment variable dynamically
by BrowserUk (Patriarch) on Jan 01, 2013 at 20:49 UTC

    The errorlevel environment variable is set to the return value from programs and scripts run by the command shell (cmd.exe). It is set by the shell.

    When you run a program from within Perl using system, there is often no command shell involved, so that environment variable does not get set.

    But, you don't need errorlevel to be set, because when you use system, you can access the return code from the program by inspecting the $? variable:

    system( q[ perl -E"exit 1;" ] ); print $? >> 8;; 1 system( q[ perl -E"exit 2;" ] ); print $? >> 8;; 2 system( q[ perl -E"exit 3;" ] ); print $? >> 8;; 3 system( q[ perl -E"exit 123;" ] ); print $? >> 8;; 123

    There are caveats with this mechanism though. Some are universal, and some windows specific.

    1. Signed versus unsigned exit codes:

      When you extract the return value from $? this way, negative exit codes are return as positive values:

      system( q[ perl -E"exit -123;" ] ); print $? >> 8;; 133 system( q[ perl -E"exit -2;" ] ); print $? >> 8;; 254 system( q[ perl -E"exit -127;" ] ); print $? >> 8;; 129 system( q[ perl -E"exit -128;" ] ); print $? >> 8;; 128 system( q[ perl -E"exit -129;" ] ); print $? >> 8;; 127

      And things get really weird with an exit code of -1:

      system( q[ perl -E"exit -1;" ] ); print $? >> 8;; Can't spawn " perl -E"exit -1;" ": No error at (eval 26) line 1, <STDI +N> line 19. 255
    2. >
    3. Values greater than 255:

      Windows programs can return 32-bit exit codes; but perl sticks slavishly to only handling the 8-bit error codes defined by *nix circa. 1970, which means that under windows, the other 24-bits are discarded:

      system( q[ perl -E"exit 12345;" ] ); print $? >> 8;; 57 system( q[ perl -E"exit 123456789;" ] ); print $? >> 8;; 21

    There is a further caveat with system as currently implemented. If the command or program you are running cannot be found, or if the perl internals decide according to some undocumented syntax inspection that you are using "shell characters" in your command; then the program you are invoking will not be run directly by Perl, but rather a copy of cmd.exe will be run and your command will be passed to it to run.

    The problem with this is that the exit code that is returned in $? is then not the exit code from your command, but rather the exit code return by cmd.exe; which in most cases will tell you nothing about the success or failure of your command.

    Now, when perl invokes the shell to run your command, it will set the exit from your command into the errorlevel environment variable. But it will be its copy of the environment, and by the time control returns to your perl script, that command shell and its copy of the environment will have been discarded, and the exit code from your command will no longer be accessible anywhere.

    The bottom line is that the errorlevel environment variable is never useful to you from with your perl script.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: accessing an environment variable dynamically
by Tommy (Chaplain) on Jan 01, 2013 at 19:12 UTC

    Welcome to Perl (I read your profile page, glad you are jumping in).

    Now then, could you please let us know -- what is the real objective you are wanting to meet here? What is the core problem you are trying to solve? Are you trying to compare 2 directories? Is that it?

    Let's break down the problem to its simplest form and work up from there...

    --
    Tommy

      Thanks for the welcome.

      It's pretty much just what I asked in my initial post. I need to compare two folders and find out if the content is identical. I've got a BC3 script that does that. Supposedly, it sets the %errorLevel% environment variable when it's done executing and I should be able to capture that and use that value to inform my Perl script of the success or failure of that comparison, but I'm not having a lot of sucess. Thus the questions I listed.

      If this doesn't work I can parse the report generated by my BC3 script, but this SEEMED the easier option. Also, the current manual audit process specifies a BC3 comparison so I'd like to honor that. If I need to do it differently though, I think that'd be fine as long as it is accurate.

      Also, I think learning how to do this correctly will be really valuable in the long run. Scripts generally tend to do a lot of interacting with the environment they run on so becoming adept at accessing and utilizing those values seems like a smart plan.

      Thanks so much for being so willing to jump in and help another coder.

      Jennie

        Ok, so here's what you want to do: listen to BrowserUK who is brilliant with Perl on Windows. BrowserUK is right that you need to focus on the value of $? after you run your system call. Personally, I like to dig a little deeper and avoid the shell as much as possible when running system commands, so I use IPC::Open3, for example.

        But for your project here, using the system() command or qx{} will probably serve you just fine. Read the perldoc -f system documentation, and you'll see it's quite doable.

Re: accessing an environment variable dynamically
by Anonymous Monk on Jan 02, 2013 at 07:01 UTC
      much more friendly than shifting $?

      You really find $? >> 8 so hard to type? Or understand?

      'sides which, that module doesn't work on the OPs OS.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        You really find $? >> 8 so hard to type? Or understand?

        Yes, its cryptic crap, its not an API