allmail
allmail

Reputation: 133

Perl windows check existence of a directory

if (!-d $logsDir) {
    print "LOGSDIR: [$logsDir] does not exist\n";
}
else {
    print "LOGSDIR: [$logsDir] exists\n";
}

I am passing the following value to $logsDir from command line and getting the following output

LOGSDIR: [c:\temp><] exists

I do have C:\temp. I know temp>< is not a valid folder name on windows. But shouldn't -d give me the correct answer saying that this directory does not exist?

thanks

Thanks for the edit and the answer. Here is the modified code and output, it still doesn't work.

use strict;
use warnings;

my $logsDir = $ARGV[0];

if (-d $logsDir) {
    print "$logsDir exists";
} else {
    print "$logsDir does not exist!";
}

__END__

Results 
>perl test60.pl c:\temp
c:\temp exists

>perl test60.pl c:\temp^<^>
c:\temp<> exists

Thanks to melporne, I also tried this

C:\Users\XXXX>dir C:\temp
 Volume in drive C is System
 Volume Serial Number is XXXX

 Directory of C:\temp

09/16/2019  12:07 AM    <DIR>          .
09/16/2019  12:07 AM    <DIR>          ..
07/03/2019  11:50 PM               765 abcd.txt
07/04/2019  12:24 AM               765 efgh.txt
07/04/2019  12:41 AM               765 efgh.txt

and so on

C:\Users\XXXX>dir C:\temp^<^>
 Volume in drive C is System
 Volume Serial Number is XXXX

 Directory of C:\

09/16/2019  12:07 AM    <DIR>          Temp
09/15/2019  05:33 PM    <DIR>          temp1
11/19/2018  06:06 PM    <DIR>          Temp;
09/15/2019  12:31 AM    <DIR>          temparchive
               0 File(s)              0 bytes
               4 Dir(s)  yyyyyyyyyyy bytes free

I do have the above folders, so it looks like it is treating it as temp*. The above result is exactly similar to this

C:\Users\XXXX>dir C:\temp*
 Volume in drive C is System
 Volume Serial Number is XXXX

 Directory of C:\

09/16/2019  12:07 AM    <DIR>          Temp
09/15/2019  05:33 PM    <DIR>          temp1
11/19/2018  06:06 PM    <DIR>          Temp;
09/15/2019  12:31 AM    <DIR>          temparchive
               0 File(s)              0 bytes
               4 Dir(s)  yyyyyyyyyyy  bytes free

Upvotes: 2

Views: 448

Answers (3)

rai-gaurav
rai-gaurav

Reputation: 556

In windows, if you try to rename(or add) a folder with '<' or '>' character you will get error -

A filename cannot contain any of the following characters: \ / : * ? " < > |

So a file or folder is not supposed to contain these characters. I tried to do multiple runs on my machine similar the program mentioned by you-

1. .\directoryexist.pl c:\Perl64              <--    Exist
2. .\directoryexist.pl c:\Perl64<>            <--    Exist
3. .\directoryexist.pl c:\Perl64^<>^          <--    Exist

Now the same thing with double quotes-

4. .\directoryexist.pl "c:\Perl64"            <--    Exist
4. .\directoryexist.pl "c:\Perl64<>"          <--    Exist
5. .\directoryexist.pl "c:\Perl64^<^>"        <--    Not Exist

Now I looked at the answer here - How can I add greater than and less than into a batch file variable which contains the great explanation of this behavior.

Basically the gist is-

Adding '^' before '<' sets the value of "c:\Perl64^<^>" to "c:\Perl64<>" without any affect. When we used double quotes around our input it is taken as it is conataing '^' hence giving the output 'not exist'.

Now, As I mentioned before you cannot have certain character in names. So, when you are checking the existence of "c:\Perk64<>" it is converted to (I hope, but right now I do not have any proof for support) "c:\Perl64" which exist.

Upvotes: 0

melpomene
melpomene

Reputation: 85767

The problem lies deeper than Perl. I wrote the following C code to compare:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s NAME\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *name = argv[1];
    struct stat st;
    if (stat(name, &st) == 0) {
        printf("stat(%s): success\n", name);
        switch (st.st_mode & S_IFMT) {
            case S_IFBLK:  printf("block device\n");            break;
            case S_IFCHR:  printf("character device\n");        break;
            case S_IFDIR:  printf("directory\n");               break;
            case S_IFIFO:  printf("FIFO/pipe\n");               break;
            case S_IFREG:  printf("regular file\n");            break;
            default:       printf("unknown?\n");                break;
        }
        return EXIT_SUCCESS;
    }
    printf("stat(%s): error: %s\n", name, strerror(errno));
    return EXIT_FAILURE;
}

(Perl's -d operator is just sugar around a stat call.)

I compiled it using the (MinGW) gcc that comes with Strawberry Perl:

gcc -Wall -Wextra -pedantic prog.c -o prog

It gives the same results:

C:\***>.\prog "C:\temp<>"
stat(C:\temp<>): success
directory

Thinking that it might be a quirk with the MinGW libraries, I tried the built-in dir command:

dir "C:\temp<>"

Curiously it doesn't fail, but it lists C:\ (not C:\temp<>) and shows only the Temp entry, not the rest of C:\.

I'm not sure what's going on here.

Upvotes: 2

Taylor Goodall AU
Taylor Goodall AU

Reputation: 214

try this

if (-d $logsDir) {
    print "$logsDir exists";
} else {
    print "$logsDir does not exist!";
}

Upvotes: 0

Related Questions