【问题标题】:What does if( -f <filename> ) in Perl do?Perl 中的 if( -f <filename> ) 有什么作用?
【发布时间】:2011-09-04 14:28:09
【问题描述】:

我遇到了这行代码:

if( -f <filename> ) { ... }

-f 似乎在测试文件名是否存在,但我不确定。到目前为止,谷歌搜索没有帮助(谷歌很难找到“-f”),我的 Perl 书籍也没有。

谁能给点建议?

【问题讨论】:

  • -f 选项相当奇怪。存在的测试是-e,但-f 是“普通文件”,似乎被定义为“不特殊”。它不是二进制的,因为在我的测试中,-B-f 的文件都返回 true。
  • 这里要吸取的教训不是依赖一般的 Google 结果。 Restrict to the domain perl.org:第二个结果就是你想要的。 – 如果不提​​及-f,您的书会非常糟糕。最好得到这些:p3rl.org/book> books.perl.org> 还有一些关于 Stack Overflow 的好建议,搜索标签 [perl][books]
  • -f 只不过是那句熟悉的老歌(statbuf.st_mode &amp; S_IFMT) == S_IFREG 的语法糖。这里的实际问题是&lt;filename&gt; 是什么,这更有趣。
  • 假设您没有重载所有 -X 前缀一元运算符(要么全部重载,要么都不重载),并且还假设您没有重载 &lt;&gt;circumfix 迭代运算符, 然后&lt;filename&gt; 将执行scalar readline(*filename) — 这取决于$/ 的值 — 然后将该结果传递回 filetest 运算符。 If 也会对&lt;$filename&gt; 执行此操作,但现在$filename 是一个间接句柄,而不是像filename 这样的直接句柄。但是,如果 filename 不是合法标识符,则使用该参数调用 File::Glob::bsd_glob 函数。

标签: perl file


【解决方案1】:

perlfunc

它列出了所有 Perl 内置函数,包括“文件测试”函数:

-X FILEHANDLE
-X EXPR
-X DIRHANDLE
-X

其中-X 是以下之一:

-r: File is readable by effective uid/gid.
-w: File is writable by effective uid/gid.
-x: File is executable by effective uid/gid.
-o: File is owned by effective uid.

-R: File is readable by real uid/gid.
-W: File is writable by real uid/gid.
-X: File is executable by real uid/gid.
-O: File is owned by real uid.

-e: File exists.
-z: File has zero size (is empty).
-s: File has nonzero size (returns size in bytes).

-f: File is a plain file.
-d: File is a directory.
-l: File is a symbolic link.
-p: File is a named pipe (FIFO), or Filehandle is a pipe.
-S: File is a socket.
-b: File is a block special file.
-c: File is a character special file.
-t: Filehandle is opened to a tty.

-u: File has setuid bit set.
-g: File has setgid bit set.
-k: File has sticky bit set.

-T: File is an ASCII text file (heuristic guess).
-B: File is a "binary" file (opposite of -T).

-M: Script start time minus file modification time, in days.
-A: Same for access time.
-C: Same for inode change time (Unix, may differ for other platforms)

【讨论】:

  • 另外,您不必“只知道”文档在 perlfunc 页面中即可获取此文档。您可以通过perldoc -f -f 找到-f 的文档 - 就像您可以通过perldoc -f some_function 找到其他功能的文档一样。
  • 普通文件的定义是什么?只是问问。
  • @JerryLam 不是目录、fifo、套接字等
【解决方案2】:

在 Unix 中,目录可以包含以下类型的文件:

  • 普通(您认为是文件)
  • 目录
  • 命名管道
  • 命名套接字
  • ...

-f 测试提供的名称是否引用了一个普通文件。如果文件不存在,它将返回 undef(错误 ENOENT),如果文件存在但它不是普通文件(例如,如果它是一个目录),则返回一些其他错误值。

-X operators

【讨论】:

    【解决方案3】:

    【讨论】:

      【解决方案4】:

      if (-f &lt;filename&gt; ) { ... }

      看来要么我误解了这个问题,要么其他人都误解了。

      首先,让我们做一些假设。

      1. 假设您没有重载所有 -X 前缀一元运算符(要么全部重载,要么都不重载),

      2. 我们还假设您没有重载 &lt;&gt; 环绕迭代运算符。

      假设上面给出的这两个给定都应该成立,那么符号 &lt;filename&gt; 将执行 scalar readline(*filename) — 这取决于 $/ 的值 — 然后将该结果传递回 filetest 运算符以供后续使用评估,通常但不一定通过 stat(2)。这意味着您最好打开一个名为 filename 的文件句柄才能正常工作,除非涉及到真正的深奥魔法。

      If 也会对 &lt;$filename&gt; 执行此操作,但现在 $filename 是间接句柄,而不是像 filename 这样的直接句柄。同样,$/ 受到尊重。使用适合与其关联的文件句柄的文件名实际上是我在整个术语中所做的事情。例如:

      our $fn = "/etc/termcap";
      open($fn, "<", $fn) || die "can't open $fn: $!";
      

      这样warndie 消息实际上告诉我文件的名称。例如:

      while (<$fh>) {
           warn "oops" if whatever;
      }
      

      会告诉我运行时所在的文件的行号和名称。

      现在,如果&lt;⋯&gt; 的操作数偏离了允许的无括号与格对象的规则,即以零个或多个美元符号为前缀的裸词,那么它不是迭代运算符而是通配符爆发器。即使没有通配符也是如此。它只需要违反 Perl 著名的与格规则,然后触发备用

      这意味着当且仅当 filename 不是带有零个或多个前导美元符号的合法裸字——例如/etc/termcap/tmp*.[Cchy]{,/usr}/bin/c?~/Documents — 然后调用 File::Glob::bsd_glob 函数指南中熟悉的旧聚合运算符,当提供适当的函数时,您会期望得到这样一个有用且常用的函数的那种结果论据。

      这里有很多例子,显示了上面引用部分实际提出的问题的答案:

      use v5.10;  # for the say feature, but not needed for conglobulation
      
      if (-d <~joebob>                 ) { say "joebob has a home"                 }
      if (-d <~joebob/.opera>          ) { say "joebob has an opera directory"     }
      if (-d <~joebob/.ssh>            ) { say "joebob has an ssh directory"       }
      
      if ($n = grep {-e} <~joebob/.*rc>) { say "joebob has $n RC files"            }
      
      if (-f <~joebob/.exrc>           ) { say "joebob has a vi config file"       }
      if (-f <~joebob/.profile>        ) { say "joebob has a sh profile"           }
      if (-f <~joebob/.bashrc>         ) { say "joebob has a bash config script"   }
      if (-f <~joebob/.cshrc>          ) { say "joebob has a csh config script"    }
      if (-f <~joebob/.log{in,out}*>   ) { say "joebob has csh login/out scripts"  }
      
      if (-S </tmp/.X*/X*>             ) { say "I smell an X11 socket"             }
      
      if (-t STDIN && -t STDOUT        ) { say "smells pretty tty to me"           } 
      

      【讨论】:

      • 我怀疑 OP 的意思是 &lt;filename&gt; 作为“文件名的占位符”而不是文字代码。即使他们确实指的是那个代码,关于为什么这可能是一个错误的讨论对 OP 来说比一篇关于 &lt;&gt; 可以做的所有事情的论文更有用。
      • @Schwern:问题是我自己确实写了open(FH, &lt;~tchrist/foofile&gt;) 这样的东西,所以if -f &lt;whatever&gt; 在tchrist™ 代码中是完全正常的。对于元句法,我更喜欢open( ʜᴀɴᴅʟᴇ, ᴍᴏᴅᴇ, ɴᴀᴍᴇ ) || die 之类的东西,因为我可以摆脱它;也就是说,使用 ᴏʙʟɪQᴜᴇ sᴍᴀʟʟᴄᴀᴘs 作为元句法(“metasyntagmata”?)。但在这里不能完全做到这一点。有些人像我在uniprops 中那样使用‹ᴡʜᴀᴛᴇᴠᴇʀ›,但在我看来,这几乎太像&lt;ᴡʜᴀᴛᴇᴠᴇʀ&gt;
      • 我确定您确实使用过它。我也会做一些古怪的事情。我会建议大多数其他程序员反对的事情,因为你在回答问题时必须考虑你的听众。而且观众不像我们。我们是第 99 个百分位,可以将闪电枪提高到 10 个。
      【解决方案5】:

      它测试&lt;filename&gt;指定的对象是否是一个普通文件(而不是二进制文件,或者是一个目录等)。

      【讨论】:

      • 二进制?如果您的意思是非文本,它们也是纯文件。 -f 用于区分不同的类型(如目录、FIFO、socket等),而不是不同的内容。
      • 与二进制不相反。它与“特殊”相反。
      猜你喜欢
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 2015-12-26
      • 1970-01-01
      • 2013-06-11
      • 1970-01-01
      • 2013-03-10
      相关资源
      最近更新 更多