http://qs1969.pair.com?node_id=11105937

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

A quick background: I have Windows 10 with Cygwin installed; I mostly use Cygwin for command line work; I have Perl 5.30.0 installed using Perlbrew.

A quick current situation: I needed Strawberry Perl for a work project; I've just installed 5.30.0 without incident. Output from scripts varies as follows: double-clicking script in File Explorer - output to a separate window (sort of expected); calling perl ./script.pl from the command line - output appears after command (expected); calling ./script.pl from the command line - output to a separate window (unexpected).

Here's some details.

I wanted to check that the correct Perl interpreter was being used. Noting that the output window disappeared almost immediately after double-clicking in File Explorer, I added some code to handle that. Here's the script:

#!/usr/bin/env perl use 5.012; use warnings; say "Platform: $^O"; say "Executable: $^X"; if ($^O eq 'MSWin32') { print 'Enter to close window: '; <>; }

This all worked as expected from Cygwin:

ken@titan /cygdrive/c/Users/ken/tmp $ ./test_platform.pl Platform: cygwin Executable: /home/ken/perl5/perlbrew/perls/perl-5.30.0/bin/perl ken@titan /cygdrive/c/Users/ken/tmp $ perl ./test_platform.pl Platform: cygwin Executable: /home/ken/perl5/perlbrew/perls/perl-5.30.0/bin/perl

What I got with MSWin has raised two questions.

Double-clicking on the script in File Explorer gave the correct output (in a separate window) with the expected prompt:

Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window:

Running as an argument to perl from the command line still has the prompt (which I'd like to get rid of):

PS C:\Users\ken\tmp> perl ./test_platform.pl Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window:

Running without perl returns immediately:

PS C:\Users\ken\tmp> ./test_platform.pl PS C:\Users\ken\tmp>

but a separate window has the (correct) output:

Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window:

Two Questions:

  1. Is there a way to identify when the output is being presented in a separate window (such that I could change the code so that the "Enter to close window:" prompt only appears in these cases)?
  2. Why does ./test_platform.pl use a separate window for output when perl ./test_platform.pl does not?

— Ken

Replies are listed 'Best First'.
Re: Handling MSWin Script Output -- ParentPID
by Discipulus (Canon) on Sep 11, 2019 at 09:32 UTC
    Hello kcott,

    > Is there a way to identify when the output is being presented in a separate window (such that I could change the code so that the "Enter to close window:" prompt only appears in these cases)?

    Yes you can, and the solotion was already at pm: Re: Re: Re: Parent process name but is slow because it processes all PIDs to get one matching $$ (I wonder if this can be shortened..) using the cpan Win32::Process::Info module.

    Here an adapted solution:

    use strict; use Win32::Process::Info; my $pihandle = Win32::Process::Info->new(); my @procinfo = $pihandle->GetProcInfo(); my $ParentPID; my %ProcNames; foreach my $PIDInfo (@procinfo) { $ProcNames{$PIDInfo->{ProcessId}} = $PIDInfo->{Name}; if ($PIDInfo->{ProcessId} == $$) { $ParentPID = $PIDInfo->{ParentProcessId}; last; } } print "Parent's name is [", $ProcNames{$ParentPID}, "]\n"; if ( $ProcNames{$ParentPID} eq 'OpenWith.exe' or $ProcNames{$ParentPID +} eq 'explorer.exe') { print 'Press ENTER to close the window: '; <>; } else{ print "..exiting normally\n"; }

    Calling the above program from command line (I always use the longhish form: perl program.pl because I do not want to mess with assoc and friends and .pl is associated just with the editor ;) the program exit directly:

    Discipulus@works:D>perl parentpid01.pl Parent's name is [cmd.exe] ..exiting normally

    But right clicking the file and using Open with and browsing to the current perl.exe I get:

    Parent's name is [explorer.exe] Press ENTER to close the window:

    Weirdly (well nothing is normal on this OS) the first time I got that the program was called by OpenWith.exe but once perl.exe is in the cached list of Open With.. the caller became explorer.exe which I suppose is the same if you double click it and you have its extension associated to perl.exe

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      G'day Discipulus,

      Firstly, sorry for the late response. I had some fairly major dental work last week: I've spent the last few days recovering and doing little else.

      Thanks for the script and examples. I imagine that code could be put into a module; perhaps used something (very roughly) like:

      ... use if $^O eq 'MSWin32', Win32::Exit::Prompt => 'exit_prompt'; ... exit_prompt() if $^O eq 'MSWin32'; exit;

      That's still extra code for every script and, as you say, it "is slow".

      As running Perl scripts directly from Win10, instead of from Cygwin, is likely to be an infrequent requirement for a $work task — at least for the time being — I'll probably be looking at handling this in the following order:

      1. Run scripts without extra code from cmd.exe (see discussion under VinsWorldcom's response).
      2. Run scripts without extra code from a possibly reconfigured PowerShell (see discussion under Orangutan's reply).
      3. Run scripts with your extra code from anywhere.

      — Ken

Re: Handling MSWin Script Output
by VinsWorldcom (Prior) on Sep 10, 2019 at 21:26 UTC

    I think it has to do with how .pl files are handled by Windows. This may come down to `assoc` and `ftype` or maybe in the registry. For me (from a cmd.exe prompt, this won't work in PowerShell):

    VinsWorldcom@:C:\Users\VinsWorldcom\tmp> assoc | find /i "perl" .pl=Perl_program_file VinsWorldcom@:C:\Users\VinsWorldcom\tmp> ftype | find /i "Perl_program +_file"

    Notice, the `ftype` command (for me) returns nothing, but if I look in my registry at HKEY_CLASSES_ROOT\Perl_program_file, I have some subkeys:

    HKEY_CLASSES_ROOT Perl_program_file shell Execute Perl Program command = [REG_SZ] C:\Strawberry\perl\bin\perl.exe "%1" %*

    Now when I run your commands, with ./ or .\ and with or without `perl` (and also with or without the .pl extension as I have my PATHEXT environment variable to include .pl) from PowerShell and / or CMD.exe, in all the combinations of the above criteria that make sense, I get the same output:

    PowerShell

    PS VinsWorldcom ~\tmp > .\test.pl Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: PS VinsWorldcom ~\tmp > ./test.pl Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: PS VinsWorldcom ~\tmp > perl .\test.pl Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: PS VinsWorldcom ~\tmp > perl ./test.pl Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: PS VinsWorldcom ~\tmp > ./test Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: PS VinsWorldcom ~\tmp > .\test Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: PS VinsWorldcom ~\tmp >

    CMD (note: CMD.exe won't interpret / as \ like PowerShell does)

    VinsWorldcom@:C:\Users\VinsWorldcom\tmp> .\test.pl Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: VinsWorldcom@:C:\Users\VinsWorldcom\tmp> perl .\test.pl Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: VinsWorldcom@:C:\Users\VinsWorldcom\tmp> .\test Platform: MSWin32 Executable: C:\Strawberry\perl\bin\perl.exe Enter to close window: VinsWorldcom@:C:\Users\VinsWorldcom\tmp>

      G'day VinsWorldcom,

      I got the same as you for 'assoc' and 'ftype' in cmd.exe:

      C:\Users\ken\tmp>assoc | find /i "perl" .pl=Perl_program_file C:\Users\ken\tmp>ftype | find /i "Perl_program_file" C:\Users\ken\tmp>

      In the registry, I have exactly the same as you (except I have C:\Users\ken\local\opt\strawberry_perl\5_030_000\install instead of your C:\Strawberry).

      In your PowerShell output, you show everything output to the PowerShell, instead of the commands starting with perl being output in a separate window. Did you do something else to achieve that?

      In cmd.exe, I get much the same as you:

      C:\Users\ken\tmp>perl .\test_platform.pl Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window: C:\Users\ken\tmp>.\test_platform.pl Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window: C:\Users\ken\tmp>perl test_platform.pl Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window: C:\Users\ken\tmp>test_platform.pl Platform: MSWin32 Executable: C:\Users\ken\local\opt\strawberry_perl\5_030_000\install\p +erl\bin\perl.exe Enter to close window: C:\Users\ken\tmp>

      So, the answer to Question 1 seems to be to remove the

      if ($^O eq 'MSWin32') { print 'Enter to close window: '; <>; }

      and run all scripts from "cmd.exe".

      — Ken

        I didn't do anything different - all output showed in the PowerShell window I ran the command from - no new window was launched.

        And just a note, I use PowerShell now exclusively - I never use CMD.exe anymore. PowerShell, I've learned, is sooooo much more capable and I've grown to love it over the past year (yes, I was a late adopter - much like how I'm now picking up Python much to my chagrin since everyone at $work uses it).

Re: Handling MSWin Script Output
by Orangutan (Novice) on Sep 10, 2019 at 18:28 UTC

    Hello Ken, I'm not a guru or a big fan of windows, but I think I can answer question 2.

    It all comes down to how windows 'luanches/executes' the script. First I want to mention that (on my windows powershell at least), it does not complain if I type:

    ./pm_11105937.pl
    vs.
    .\pm_11105937.pl
    or:
    perl ./pm_11105937.pl
    vs.
    perl .\pm_11105937.pl
    and, in fact the autocomplete will complete to:
    .\pm_11105937.pl
    which is a subtle but I think important distinction. You might also want to look at the Unix 'source' command to see what the './' means to a bash shell. So to see how windows is executing these open the task manager next to the powershell terminal and watch whats running when you execute with:
    ./pm_11105937.pl
    vs.
    perl pm_11105937.pl
    We can see that when the script is invoked with 'perl <.pl>' the perl interpreter is running in the powershell, but when invoked by itself with './<.pl>' the powershell is starting a seperate perl interpreter instance(?) to run the script.

    As for question 1 though, I'm not sure, but I think there would be a way to do it with some command-line switches, for which you might find some wisdom in perldoc perlrun.

    Hope I could help shed some light at least.

      G'day Orangutan,

      Yes, I found out about the './ and '.\ early on when I tried just 'test_platform.pl'. There was a lot of output, which I won't post here; however, the last part of that had 'Suggestion [3,General]: The command test_platform.pl was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\test_platform.pl". ...'.

      This is pretty much the same as UNIX-like systems when '.' is not in the path. Using my Cygwin:

      $ test_platform.pl -bash: test_platform.pl: command not found $ ./test_platform.pl Platform: cygwin Executable: /home/ken/perl5/perlbrew/perls/perl-5.30.0/bin/perl

      So, from PowerShell

      perl test_platform.pl perl ./test_platform.pl perl .\test_platform.pl

      all work identically to how I described 'perl ./test_platform.pl' in the OP. And

      ./test_platform.pl .\test_platform.pl

      both work identically to how I described './test_platform.pl' in the OP.

      Anyway, what you've described regarding how the Perl interpreter is called, does make sense, and probably answers Question 2. It's a pity, because I'd prefer not to have to type 'perl' before every script name; still, it is only for a work project and won't generally affect me as I'm normally using Cygwin.

      I also noticed that you'd signed up only a fortnight ago; so please accept a belated welcome to the Monastery.

      — Ken

        Hello again, I think I learned something too, cmd indeed does run either call of the script in it's own window, only powershell opens the other window. And yeah if it's only for a minor convenience I suppose it might not be worth sinking too much time into :), but to throw some other suggestions out there, there does seem to be alot of possible ways to configure the powershell, or maybe wrap the script in a batch file or call from a batch file, and there also seems to be a 'legacy console' mode for powersell but I havent tried it.

        Thanks for the welcome.

Re: Handling MSWin Script Output
by Anonymous Monk on Sep 10, 2019 at 08:43 UTC
    Why do you have more than one? Why don't you know about path, assoc, ftype?