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

All I need to do is test to see if a file exists! Seems easy right? Well, apparently not. Below you will see a few things I have tried. The only thing that works is actually chdir()'ing to the directory (notice that took two chdir()'s to get there. When I was doing just one chdir() the script never warn()'ed it just never actually got to the desired directory. When I wrote code to actually do a listing (using readdir()) it was not in the destination directory that it said it was in...it was in the parent directory to that directory. I checked permissions, I checked to make the file actually existed, I think I have checked all but the one thing causing my problem...this is why I am here.

my $funcName = (caller(0))[3]; my $player_name = shift; my $mapname = shift; (my $gamedir = &send(1,"sv_gamedir")) =~ s/.*: (.*)\n+/$1/; my $full_path = "$HOME/$gamedir/maps/$mapname.bsp"; # chdir("$HOME/$gamedir") or # die("Cannot chdir to $HOME/$gamedir: $!\n"); # chdir("maps") or # die("Cannot chdir to maps: $!\n"); # print "Current working directory: " . getcwd . "\n"; if ( -f $full_path ) { print STDERR "Map exists! -> $HOME/$gamedir/maps/$mapname.bsp\ +n"; &send(0,"say Player name: $player_name map: $mapname"); } else { print STDERR "Map does not exist! -> $HOME/$gamedir/maps/$mapn +ame.bsp\n"; &send(0,"say Requested vote for map $mapname denied: map does +not exist on this server"); }

----------
- Jim

Replies are listed 'Best First'.
Re: From chat to here :) chdir() and test -f issues.
by MZSanford (Curate) on Jul 04, 2001 at 14:27 UTC
    In debugging tons of code, i have found one other thing that often causes issues is non-printing charachters. While from the code i would not imagine that is the issue, when you can see a file that a script cannot,it is usually either :
    A: Permissions (see above post)
    B: Wrong file name (test using "| cat -v" to find non-printing)

    Just thnking, the code s/.*: (.*)\n+/$1/; does not remove \r if it is there ... could it be there ?
    may the foo be with you
      Ok. Im gonna test to see if there are any '/r's in the string but I can't seem to think of a good way to see non-printing characters in a string (cat only works while streaming the contents of files afaik.) Anyway, if anyone has any good ideas on this one Im open to them.

      On the other hand, the only thing that still wags my head on this is the fact that if I break the chdir()'s up into seperate changes (ie :

      chdir("$HOME/$gamedir/maps"); # does not work in the script
      vs

      chdir("$HOME/$gamedir"); chdir("maps"); # works fine.
      )

      This still makes me wonder...why would invisible characters cause problems for the first example but not for the second. This is the question I was originally getting at, although I don't think I stated it very well. :) Come on! It was 430AM =).

      Anyway, Im curious to see if anyone can answer that one. Thanks again guys.

      ----------
      - Jim

      Ah, this was excellent for helping working on my debugging abilities. Here is what I did.

      I ran a regex on the $gamedir variable to match the first non-character character and replace it with a "*". Sure enough there was an invisible character at the end of the string but I do not think it was a '\r' as I had already used s regex to strip '\r' (admittedly I may have done that part incorrectly though)...code to follow. Anway, I decided to simply chop() the last character (hoping there was only one) and that worked. Here is the code and output:

      Finding the problem

      my $funcName = (caller(0))[3]; my $player_name = shift; my $mapname = shift; (my $gamedir = &send(1,"sv_gamedir")) =~ s/.*: (.*)[\r\n]+/$1/; (my $testgamedir = $gamedir) =~ s/\W/*/; print STDERR "\$HOME = $HOME\n\$testgamedir = $testgamedir\n\$mapn +ame = $mapname\n";

      output:

      $HOME = /services/qw $testgamedir = fortress* $mapname = 2fort5 Map doesn't exist! -> /services/qw/fortress/maps/2fort5.bsp

      As we can see by the

      fortress*
      that there was at least one white character there.

      After chop()

      my $funcName = (caller(0))[3]; my $player_name = shift; my $mapname = shift; (my $gamedir = &send(1,"sv_gamedir")) =~ s/.*: (.*)[\r\n]+/$1/; chop($gamedir); (my $testgamedir = $gamedir) =~ s/\W/*/; print STDERR "\$HOME = $HOME\n\$testgamedir = $testgamedir\n\$mapn +ame = $mapname\n";
      output:

      $HOME = /services/qw $testgamedir = fortress $mapname = 2fort5 Map exists! -> /services/qw/fortress/maps/2fort5.bsp

      ----------
      - Jim

Re: From chat to here :) chdir() and test -f issues.
by tadman (Prior) on Jul 04, 2001 at 13:12 UTC
    I'm only guessing here, but I think that the user that is running the script is not able to see the file, while the user that you are running the diagnostics under can. An easy way to diagnose this is to 'su' to that user and see if you can see those files in the shell. The harder way is to dump a readdir() listing to STDERR.

    This might be because a single directory somewhere along that path is not mode 0755, but perhaps 0700 or somesuch. In order to get into the final directory, you have to enter each in turn.

    As an aside, it is odd that you list the code $HOME/$gamedir/maps/$mapname.bsp in no fewer than three places in your code. If you were to change one, for whatever reason, the other two would be desynchronized (read: not working). A good idea is to warn with the actual thing you were testing, not a simulation.
Re: From chat to here :) chdir() and test -f issues.
by stefan k (Curate) on Jul 04, 2001 at 14:25 UTC
    Hi,
    I'd follow tadman here, that I suspect a USER thing. Do you run the script under different users? Maybe give out some diags at the beginning: what is the actual value of $HOME, du you get it from %ENV?, what is the actual username that run the script (print $ENV{'USER'}) and the like ...

    If you got that you could split the $gamedir at the pathseparators (/) and subsequently chdir to them to find out whether there are some permission in the way. Something like

    foreach (split/\//,$gamedir) { next if ($_ eq ""); print "Changing to $_\n"; chdir($_) or die "error in $_"; }

    Regards... Stefan

Re: From chat to here :) chdir() and test -f issues.
by converter (Priest) on Jul 04, 2001 at 19:15 UTC

    Don't waste your time guessing. Perl provides the answer:

    $ perl -e 'if (-f "foobarama") { print "file exists" } elsif ($!) { pr +int "$!\n" }' No such file or directory $ perl -e 'if (-f "/root/foobarama") { print "file exists" } elsif ($! +) { print "$!\n" }' Permission denied
      Yup. Already did this. And from the command line it works fine. BTW, I am running the script as the user that is running the script or in other words, I have pretty much eliminated a permissions issue. Anyway, I am getting closer and I believe those of you who stated that there maybe a hidden character somewhere must be on the right track...

      [qadmin@concon qw]$ perl -e ' $gamedir = "fortress"; $HOME = $ENV{'HOME'}; $mapname = "2fort5"; if ( -f "$HOME/$gamedir/maps/$mapname.bsp" ) { print "It exists!\n" } +else { print "$!\n" }; ' It exists! [qadmin@concon qw]$ perl -e ' $gamedir = "fortress"; $HOME = $ENV{'HOME'}; $mapname = "2fort5qra"; if ( -f "$HOME/$gamedir/maps/$mapname.bsp" ) { print "It exists!\n" } +else { print "$!\n" }; ' No such file or directory [qadmin@concon qw]$

      Since the script uses other means whereby to get these values and it doesn't work vs my putting these values in by hand where I know there are no hidden characters I can deduce that there must be some hidden character slipping in somewhere in the runtime of the script. I don't see why there would be a '\r' in this thing but it is possible so I will try that out and see how I fare. A '\r' seems like the most logical thing that could be flubbing this up.

      Thanks fellow monks. I will let everyone know the outcome once I am done.

      ----------
      - Jim

Re: From chat to here :) chdir() and test -f issues.
by Anonymous Monk on Jul 05, 2001 at 01:56 UTC
    If the hidden character is a '\0' it denotes an end of string for the purposes of the file system.If you do
    chdir("$HOME/$games/maps"); #hidden \0 here ^
    you will actually chdir to $HOME/$games. No mapfile there. In two stages you will first land in the same dir, but you will know it and not expect the mapfile before stage 2.
      This is exactly what happened.

      ----------
      - Jim

Re: From chat to here :) chdir() and test -f issues.
by snafu (Chaplain) on Jul 04, 2001 at 12:50 UTC
    update: I thought some sample output would be helpful.

    Wed Jul 4 04:43:02 2001-> DEBUG at 266 : Request main::send Map does not exist! -> /services/qw/fortress/maps/2fort5.bsp
    That came from the code mentioned in my first post. However, here is the fs image:

    [qadmin@concon logs]$ ls -l ~/fortress/maps/2fort5.bsp -rw-r--r-- 1 qadmin qadmin 922568 Jun 29 2000 /services/qw/fo +rtress/maps/2fort5.bsp [qadmin@concon logs]$ ls -ld ~/fortress/maps/ drwxr-xr-x 2 qadmin qadmin 2048 Apr 12 22:37 /services/qw/fo +rtress/maps/

    and to break it down:

    $HOME = /services/qw $gamedir = /fortress maps = manually placed 2fort5 is from parent function .bsp is manually placed

    ----------
    - Jim