Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Strawberry Perl on Windows 10 file test operators do not work as expected

by fireblood (Scribe)
on Jul 22, 2020 at 20:24 UTC ( [id://11119676]=perlquestion: print w/replies, xml ) Need Help??

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

I'm running Strawberry Perl 5.30 on Windows 10, and am finding that the test -e 'C:\Users' resolves to a false value; in fact the -e operator operating on any valid, existing entity (file name or directory name) always returns a false value.

I recall that in the past I've found that the file test operator -r also does not work as expected under Strawberry, because when my program first uses -r to verify that a file is readable before attempting to read it, and on getting a true value then goes on to read it, can still find that the file is in fact unreadable.

Why is this? I would have thought that when Strawberry Perl was created as the primary Windows port of Perl that the code for the -e, -r, and other single-letter file tests would have been rewritten using Windows-friendly code to provide the same return values for Windows files that their UNIX counterparts do for UNIX files.

As to a workaround, is there any sort of switch that I can set anywhere in my Windows environment or perl program that will tell perl to cause the one-letter file test operators to behave analogously to how they do in UNIX?

If not, I've been examining the Test::File CPAN module. Its methods do work the way that I need them to, e.g. the file_exists_ok() and file_readable_ok() methods are effective replacements for the -e and -r file test functions. However, the use of the Test::File module comes at a price --

(1)the total number of tests that are to be performed during the entirety of the program run needs to be specified in advance (via the specification of the File::More module that must come first) notwithstanding that the number of tests may not in fact be knowable in advance, such as in a directory tree traversing and searching program;

(2) the Test::File module writes the results of its testing to stdout or stderr (depending on the outcomes of the tests) and I have not found anything in the Test::File documentation to get it to just silently perform its tests and do nothing more than simply provide true or false return values;

(3) I store the majority of my perl programs on a network drive where they can be invoked from either a Windows or a Linux environment. In my programs' initialization routines, they need to examine the value of $^O and behave accordingly. When the value of $^O is "MSWin32", then they need to say "use Test::Main tests => <whatever>" and "use Test::File". Otherwise (when the value of $^O is, say, "linux"), then the preceding two use instructions are never executed, but being in the program code they are nonetheless parsed. I have the Test::More and Test::File modules installed in my Windows CPAN directory from which they are loaded and executed, but because any program that includes these two use instructions is likely also to be invoked from a Linux environment these two modules would need to be included in my Linux CPAN directory as well, never to be executed but only to keep a program from failing during the initial parsing step because they appear as targets of use instructions (which are never executed but nonetheless parsed). Having them in the Linux CPAN directory only for syntactic considerations seems kludgy and problematic.

I can squelch the unwanted verbose output by relegating the use of TEST::FILE to eval blocks, and I can create a function that returns a true or false value to indicate whether or not a specified file or directory exists by listing the members of its parent directory and checking to see if any of the member names matches the specified name and is of the same type (file vs. directory), but this all seems like a lot of effort to have to go to just to check within the Strawberry Perl environment for Windows whether or not a given file or directory exists and/or is readable.

Given the ubiquity of Windows, I'm sure that this file test operator issue that I'm describing has been encountered countless times before. What have others done that have turned out to be good alternatives?

Replies are listed 'Best First'.
Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by choroba (Cardinal) on Jul 22, 2020 at 21:00 UTC
    > -e "C:\Users" resolves to a false value

    Are you sure you used exactly this syntax? No wonder the file doesn't exist:

    perl -wE "say qq<C:\Users>" C:SERS

    \U in double quotes uppercases the following letters up to \E or end of the string.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Hi choroba, yes, you are correct, and in my actual code I did include the backslash escape character before the backslash path separator character (i.e. a double backslash) but did not have it in the code example that I typed in. I have updated my post to use single quotes rather than double quotes in that particular spot. Thanks for spotting that.
Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by swl (Parson) on Jul 22, 2020 at 22:16 UTC

    Works for me (see below).

    Cases where it does not work are where there are unicode chars in the file names, which is when Win32::LongPath is very useful.

    perl -We "print -e 'C:\Users'" 1
    perl -v This is perl 5, version 30, subversion 0 (v5.30.0) built for MSWin32-x +64-multi-thread Copyright 1987-2019, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using "man perl" or "perldoc perl". If you have access to + the Internet, point your browser at http://www.perl.org/, the Perl Home Pa +ge.
Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by dasgar (Priest) on Jul 22, 2020 at 22:11 UTC

    It might be worth checking out testL from Win32::LongPath. It's not an exact syntax match to the -X tests, but it does provide an alternative method for those tests and provides support for any paths in Windows (including those that are longer than 255 characters in length and those using Unicode characters - both of which probably won't work with the -X tests).

    If you find testL to be an acceptable alternative to the -X tests, one possible approach to get your code to work on Linux and Windows is to write subroutines to replace the -X tests and in those subroutines to check the OS type (Linux or Windows) to determine if it will use the -X tests (for Linux) or testL (for Windows). I'm not arguing that this is a "good" approach, but just wanted to toss out the one idea that I had on the topic.

Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by afoken (Chancellor) on Jul 23, 2020 at 08:11 UTC

    Related: Windows and stat() a.k.a. -X

    And a note on backslash (\) vs. forward slash (/):

    Windows works fine with forward slashes, use them to get rid of all escaping issues of backslashes. As a welcome side-effect, this will make your code easier to port to other systems where the path sepearator is a forward slash. The only issue with forward slashes on Windows is that some old and/or stupid programs interpret forward slashes as option indicators, even when found in filenames. In that case, a simple

    tr|/|\\| for @args;

    before passing @args to the problematic program should help.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by fireblood (Scribe) on Jul 22, 2020 at 23:15 UTC

    Something else that I just discovered from reading another post seems relevant. One part of the total picture that I did not initially include in my post here is that many of the files whose existence my script is attempting to determine are on drives other than the default C: drive. In fact, to let the whole cat out of the bag, what my program is attempting to do is create a perl array that holds the identifiers of all currently mounted drives on the current system. It is based on an algorithm that I saw elsewhere where a loop like the following is executed:


    package StdHdr;
    
    	require strict;
    
    	our $OS = $^O;
    
    	our @currently_mounted_drives;
    
    	if ($OS eq "MSWin32")
    
    		{
    			do {$currently_mounted_drives@currently_mounted_drives = $_ . ":" if -e $_ . ":\\"} for ("A" .. "Z")
    		}
    
    	elsif ($OS eq "linux")
    
    		{
    			do {$currently_mounted_drives @currently_mounted_drives = "/mnt/" . $_ if -e "/mnt/" . $_} for ("a" .. "z")
    		}
    
    	1;
    

    optionally followed by
    	print "\nCurrently-mounted drives are the following:\n\n";
    
    	print "$_\n" for @StdHdr::currently_mounted_drives;
    
    	print "\n";
    

    This had been working perfectly in the Linux environment but had been failing in the Windows environment. But the tipoff to what a key part of the problem was, if not the entirety of the problem, was something that I found in a different posting entitled File Existence using "-e" not always working. There was a comment by a participant named tye who zeroed in not only on what a likely cause of the problem might be but also its solution --


    Looks like "auto mount" behavior. It is common that checking for a file's existence won't trigger the automatic mounting of the remote file system but that trying to read a file will trigger that.

    And therein lies what I think is the answer to my question. The reason why I was getting so many return values indicating nonexistence when I issued the -e command on targets that I knew existed was not because the targets did not exist, but only because they had not been mounted at the time of my inquiry, such that the -e was unable to see them and thereby impatiently provided false return values. I've made some adjustments for that in my program and now it works perfectly in both the Windows and the Linux environment.


    Thanks again to all who provided feedback, it was very instructive for me.

    P.S.:
    C:\Windows\system32>list_drives
    
    Currently-mounted drives are the following:
    
    C:
    E:
    F:
    G:
    H:
    I:
    

    rbaumann@DESKTOP-VRU1MNM:/mnt/c/Users$ list_drives
    
    Currently-mounted drives are the following:
    
    /mnt/c
    /mnt/e
    /mnt/f
    /mnt/g
    /mnt/h
    /mnt/i
    
    rbaumann@DESKTOP-VRU1MNM:/mnt/c/Users$
    

      Hello fireblood,

      I suggest to use specific tools on win32 systems:

      discupulus@:D>perl -MWin32API::File -E "say for Win32API::File::getLog +icalDrives" C:\ D:\ F:\ L:\ M:\

      Or I'd go for some system calls brutally parsing it's output (maybe after this, also -e results):

      # admin privileges not required: all drives included network ones: discipulus@:D> fsutil fsinfo drives Unità: C:\ D:\ F:\ L:\ M:\ # admin privileges not required: only network ones: discipulus@:D> net use Le nuove connessioni non saranno memorizzate. Stato Locale Remota Rete ---------------------------------------------------------------------- +--------- L: \\bip\root\work\discipulus Microsoft Windows +Network M: \\bip\ROOT\DATA Microsoft Windows Network Esecuzione comando riuscita. # admin required: only logical disks C:\WINDOWS\system32> wmic logicaldisk get name Name C: D: F:

      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.

      With the way Perl has been going, I don't know if I'd trust things like this:

      if ($OS eq "MSWin32") elsif ($OS eq "linux")

      I'm still waiting to see if Strawberry comes out with a perl 5.32 or perl 7.xx. Bizarre and frustrating times.

        if ($OS eq "MSWin32")

        That has always worked fine for the last 25 years that I've been using perl.
        However, I don't assume that it will work as expected forever.
        But then I also don't want to guess at what might be needed if the osname is changed.

        I'm still waiting to see if Strawberry comes out with a perl 5.32 or perl 7.xx

        Recent posts by kmx indicate that he has started work on the next release - see this github thread for example.
        I expect it will be perl-5.32.0, though this has not been explicitly stated any place that I know of.

        Cheers,
        Rob
Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by perlfan (Vicar) on Jul 22, 2020 at 20:34 UTC
    perlport on -X doesn't mention -e. Maybe it's a fs permission or ACL issue. C:\Users doesn't seem like it's something a non-admin user would likely be allowed to putz around with.
      Hi perlfan, yes, you are correct, C:\Users is not a directory that one would normally want to meddle in, but it is not the real directory that is of relevance to my program in which I encountered these issues, it is just a sample directory name that I picked for purposes of this post only because of its short length. Thanks for your note.
Re: Strawberry Perl on Windows 10 file test operators do not work as expected
by fireblood (Scribe) on Jul 22, 2020 at 22:18 UTC

    Well, while continuing to hack around on this I have been able to identify file names where the -e file test operator DOES in fact return the correct answer. I'm continuing to research this on my own on the side for a while, continuing on to check whether the -r file test operator works as expected, and so forth. Thanks to those who have provided feedback thusfar, it has been very instructive.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11119676]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (8)
As of 2024-04-23 09:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found