【问题标题】:What does -l $_ do in Perl, and how does it work?-l $_ 在 Perl 中有什么作用,它是如何工作的?
【发布时间】:2013-03-05 13:40:41
【问题描述】:

嵌套代码是什么意思

foreach (@items)
{
    if (-l $_)    ## this is what I don't understand: the meaning of -l
    {
        ...
    }
}

感谢您的帮助。

【问题讨论】:

  • 标准功能:我使用mkdir $directory unless (-e $directory);

标签: perl


【解决方案1】:

让我们来看看每一件事:

foreach (@items) {
    ...
}

这个for 循环(foreachfor 在 Perl 中是相同的命令)从@items 列表中获取每个项目,并将其设置为$_$_ 是 Perl 中的一个特殊变量,用作默认变量。这个想法是你可以做这样的事情:

foreach (@items) {
    s/foo/bar/;
    uc;
    print;
}

这些命令中的每一个都将对$_ 变量进行操作!如果你只说print 没有其他内容,它将打印$_ 中的任何内容。如果您说uc 并且没有提及变量,则它将大写$_ 中的任何内容。

现在不鼓励这样做有几个原因。首先,$_全局,因此可能会出现非预期的副作用。例如,假设您调用了一个带有$_ 值的子例程。你会突然惊讶于你的程序不起作用。

另一个-ltest 运算符。该运算符检查给定的文件是否是符号链接。我已经链接到解释所有测试运算符的 Perldoc。

如果您不熟悉 Unix 或 BASH/Korn/Bourne shell 脚本,那么以破折号开头的命令看起来很奇怪。然而,Perl 的大部分语法都被盗用了……我的意思是 从 Unix shell 和 awk 命令中借来的。在 Unix 中,有一个名为 test 的命令,您可以像这样使用它:

if test -L $FILE
then
    ....
fi

在 Unix 中,-Ltest 命令的参数,而在 Unix 中,命令的大多数参数都以破折号开头。 Perl 只是借用相同的语法破折号和所有。

有趣的是,如果您阅读这些测试命令的 Perldoc,您会注意到,就像 foreach 循环一样,如果您不给它一个变量或文件名,各种测试命令将使用 $_ 变量。编写该脚本的人可能会这样编写循环:

foreach (@items)
{
    if (-l)   ## Notice no mention of the `$_` variable
    {
        ...
    }
}

是的,这太清楚了!

仅供参考,许多 Perl 专家 (cough Damian Conway cough) 推荐的 现代 方法是避免 @尽可能使用 987654346@ 变量,因为它并不能真正增加清晰度并且可能导致问题。他还建议只说for 而忘记foreach,并在同一行使用花括号:

for my $file (@items) {
    if ( -l $file ) {
        ...
    }
}

这可能对-l 命令没有帮助,但至少您可以看到您正在处理文件,因此您可能会怀疑-l 与文件有关。

不幸的是,Perldoc 将所有这些文件测试放在 -X 部分并按字母顺序排列在 X 下,因此如果您在 Perldoc 中搜索 -l 命令或任何以破折号开头,除非您知道,否则您将找不到它。但是,至少您现在知道将来当您看到这样的内容时该去哪里:-s $file

【讨论】:

  • perldoc -f "-X" 工作得很好,不过。导航到perldoc.perl.org/perlfunc.html 并搜索-l 也是如此。当您说"This is now discouraged for several reasons." 时,您实际上只提到了一个原因,而另一个原因并不完全正确。 $_ 是该特定循环的别名。因此,除非您使用的子程序(意外?)出于某种原因使用了全局变量(不好的做法),否则您可以随意使用$_。我选择的原因是它更明确地说明了正在发生的事情。
  • 你说$_很特别,但唯一特别的是它总是引用$main::_,这与OP无关。
  • @ikegami $_ 特殊,因为它是某些命令使用的默认变量,并且与 OP 相关。因为它是默认变量,所以在使用时可能会产生副作用。
  • 就像你说的,特别的是有些函数会读取它。无论使用什么 var,都会产生副作用。
  • @TLP 是的,如果你知道在 Perldoc 中寻找 -X,你会找到它。而且,如果您使用网络浏览器的内置查找文本,您会找到它。而且,如果您执行命令行 Perldoc 命令perldoc -f -l,您甚至会找到它。但是,您不会通过查看函数索引找到它,如果您尝试谷歌 perl function -1 也不会找到它,这是许多人尝试做的。
【解决方案2】:

这是一个operator,用于检查文件是否为符号链接。

【讨论】:

  • 还有其他的检查方法吗?
  • 纯粹出于好奇。我维护了一些 Perl 脚本,并且正在寻找最“罗嗦”的方法来测试某些东西,包括打开文件等等,尽管有快捷方式。
  • 几乎所有的 -X 操作都使用来自stat 的信息,-l 也不例外。或者如果你想傻,你可以使用 Inline::Java 调用一个 Java 函数来做同样的事情。
  • @octopusgrabbus 您是要混淆脚本,还是只是尝试编写更“可读”的代码?
  • @TLP 好奇 + 维护 = 混淆和优化
【解决方案3】:

-l filetest operator 检查文件是否为符号链接。

-l 在底层的工作方式类似于下面的代码。

#! /usr/bin/env perl

use strict;
use warnings;

use Fcntl ':mode';

sub is_symlink {
  my($path) = @_;

  my $mode = (lstat $path)[2];
  die "$0: lstat $path: $!" unless defined $mode;

  return S_ISLNK $mode;
}

my @items = @ARGV;
foreach (@items) {
  if (is_symlink $_) {
    print "$0: link: $_\n";
  }
}

样本输出:

$ ln -s foo/bar/baz quux
$ ./flag-links 标志链接 quux
./flag-links: 链接:quux

请注意对lstat 的调用,而不是stat,因为后者会尝试跟踪符号链接但从不识别它们!

要了解 Unix 模式位的工作原理,请参阅 accepted answer to “understanding and decoding the file mode value from stat function output.”

【讨论】:

    【解决方案4】:

    来自perldoc

     -l File is a symbolic link.
    

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 2019-06-01
      • 2017-12-26
      • 2016-08-19
      • 2010-09-19
      • 2013-02-13
      • 2018-06-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多