---
name: "Perl::Critic::Policy::ValuesAndExpressions::ProhibitFiletest_f"
section: "3pm"
platform: "linux"
package: "libperl-critic-pulp-perl"
version: "99-1"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/Perl::Critic::Policy::ValuesAndExpressions::ProhibitFiletest_f"
---

# Perl::Critic::Policy::ValuesAndExpressions::ProhibitFiletest\_f(3pm)

don't use the -f file test

## NAME

Perl::Critic::Policy::ValuesAndExpressions::ProhibitFiletest\_f - don't use the -f file test

## DESCRIPTION

This policy is part of the `"Perl::Critic::Pulp"` add-on.  It asks you not to use the `"-f"` file test because doing so is usually wrong or unnecessarily restrictive.  On that basis this policy is under the "bugs" theme and medium severity, see "POLICY THEMES" in Perl::Critic.

- "-f" is not the opposite of "-d"

  If you're traversing a tree and want to distinguish files from directories to descend into, then `"-d"` should be used so device files or named pipes can be processed.

  ```
      if (-f $filename) {      # bad
        process ($filename);
      } else {
        descend ($filename);
      }
      if (-d $filename) {      # better
        descend ($filename);
      } else {
        process ($filename);
      }
  ```

- "-f" doesn't mean readable/writable/seekable

  Char specials and named pipes are perfectly good for reading and writing, and char specials can support seeking.  Demanding `"-f"` is an unnecessary restriction.  You might only ever use ordinary files normally, but there's no need to prevent someone else running it on a tape drive, */dev/null*, etc.  You always have to test each `"seek()"` etc for success anyway, and that will tell you if a file is seekable.

  ```
      seek HANDLE, 123, 0
        or die "Cannot seek: $!";
  ```

- "-e" is better than "-f"

  A few inflexible functions or operations may not have good "file not found" behaviour and may force you to check for a file before invoking.  Using `"-e"` is better than `"-f"` since as described above it doesn't unnecessarily disallow device files.

  ```
      if (-f $filename) {      # bad
        require $filename;
      }
      if (-e $filename) {      # better
        require $filename;
      }
  ```

- "-f" before opening is a race condition

  Testing a filename before opening is bad.  Any test before opening is useless because the file can change or be removed in between the test and the open ("-X" in perlfunc, and "Consider this carefully" in filetest, note this about `"-r"` etc too).

  ```
      if (-f $filename) {               # bad
        open HANDLE, '<', $filename
      }
  ```

  If you want to know if the file can be opened then open the file!  The error return from `"open()"` must be checked, so a test beforehand only duplicates that, and is an opportunity to wrongly presume what the system or the user's permissions can or can't do.

  When opening, `"ENOENT"` will say if there was no such file, or `"EISDIR"` if it's in fact a directory.

  ```
      if (! open HANDLE, '<', $filename) {  # better
        if ($! == POSIX::ENOENT()) {
          ...
        }
      }
  ```

  If you really do want to enquire into the nature of the file, in order to only accept ordinary files, then open first and `"-f"` on the handle.  But that's unusual except for an archiving or backup program.

  Incidentally, the error message in `$!` is normally the best thing to print.  It can be slightly technical, but its wording will at least be familiar from other programs and is translated into the user's locale language.

### Disabling

Most uses of `"-f"` tend to shell script style code written in Perl.  In the shell, it's usually not possible to do better than such tests (though `"-d"` or `"-e"` are still generally better than `"-f"`), but Perl can do the right thing.

A blanket prohibition like this policy is harsh, but is meant as a building block or at least to make you think carefully whether `"-f"` is really right. As always you can disable `"ProhibitFiletest_f"` from your *.perlcriticrc* in the usual way (see "CONFIGURATION" in Perl::Critic),

```
    [-ValuesAndExpressions::ProhibitFiletest_f]
```

## SEE ALSO

Perl::Critic::Pulp, Perl::Critic, "open" in perlfunc, "ERRNO" in POSIX, Errno, [**errno**(3)](/errno/3.md)

## HOME PAGE

http://user42.tuxfamily.org/perl-critic-pulp/index.html

## COPYRIGHT

Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Kevin Ryde

Perl-Critic-Pulp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Perl-Critic-Pulp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Perl-Critic-Pulp.  If not, see \<http://www.gnu.org/licenses\>.
