【问题标题】:perl - Why exit code 0 if error file not found, can I make it code 1?perl - 如果找不到错误文件,为什么退出代码 0,我可以将其设为代码 1 吗?
【发布时间】:2017-01-04 10:00:19
【问题描述】:

我有几个逻辑 AND 命令,中间是一个就地编辑文件的 perl 命令。

echo before && \
perl -pe 's/foo/bar/g' -i qux && \
echo after

如果文件不存在,perl 会报“Can't open qux: No such file or directory”。但是错误代码是 0。这是一个问题,因为我不希望命令继续。换句话说,如果文件不存在,则不应打印“之后”。为什么会发生这种情况,我该如何阻止它?

【问题讨论】:

  • 你可以echo before && test -f qux && ...
  • @dsm 是的,这似乎是一个很好的解决方法,谢谢
  • 解释器 (Perl) 返回到 shell,而不是它执行的(单行)程序。除了成功 (0) 之外,它没有理由返回任何内容。如果您要调用脚本而不是单行代码,则可以使用 exit 1
  • 另一点——输入循环是作为-p 的一部分设置的,因此没有文件是未捕获的异常,您无法控制发生的情况。你可以放弃它,比如perl -e '-f qux || exit 1; ...',然后它会按预期工作。但是当然你必须自己设置while(<>) { ... },事情变得笨拙。
  • @zdim 我很好奇有什么原因我不能这样做$SIG{__DIE__} = sub {exit 1}; 我只是尝试设置一段时间()并且没有调用 die 信号处理程序

标签: perl


【解决方案1】:

好的,所以...

正如问题的 cmets 中所述,perl 以 0 退出的原因是因为 perl 本身是成功的,即使 perl 执行的代码没有成功。为了让它在失败时退出,那么,如果文件无法打开,我们需要找到一种方法使其die(或显式exit具有非零状态)。

但是perl -p 会在您的单行代码周围包裹一个循环,所以我们可以这样做而不必在每一行上重复测试吗?我们可以! perldoc perlrun 告诉我们 BEGINEND 块允许我们在循环执行之前或之后进行控制。

但是我们仍然需要一种方法来判断文件是否被成功打开。为此,我们需要知道<> 使用的文件句柄的名称,perldoc perlvar 告诉我们称为ARGV

ARGV 仅在读取时(可靠地)具有魔力,因此我们不能只测试它是否已定义,因为(在我的快速测试中)它总是已定义,即使文件丢失。所以我们必须从中读取。然后第一行丢失了。但这很容易通过seek回到文件开头来解决。

TL;DR 以及所有这些的结果:

echo before && \
perl -pe 'BEGIN { exit 1 unless <> ; seek ARGV,0,0 } s/foo/bar/g' -i qux && \
echo after

请注意,这仍然不是 100% 完美。如果文件存在但为空,它也会die。检查defined &lt;&gt; 并不能修复此缺陷,如果文件不存在,则尝试&lt;&gt; ; die unless ARGV 会导致&lt;&gt;STDIN 读取。如果有人有办法让它正确检测空文件,我很想听听!

【讨论】:

  • 啊,这让我逃脱了。我只用-e 拼凑了一个简短的单行字,但这更好。在我的测试中,BEGIN { exit 1 if not -f $ARGV[0] or -z $ARGV[0] } 处理了这两种情况。更长,但之后就不需要seek
  • 非常好,@Zaid!我不知道eof 有这种魔力。不幸的是,它仍然无法区分空文件和丢失文件。正如@zdim 建议的那样,如果不从 Perl 代码中显式使用文件测试,似乎没有办法做到这一点。
  • 是的,我认为像BEGIN { @ARGV = grep -f &amp;&amp; ! -z, @ARGV; exit 1 if eof() || ! @ARGV } 这样的东西可以解决这个问题,但至少可以说解决方案令人眼花缭乱。我认为如果可能的话,最好将这些类型的文件检查推迟到 shell,在这种情况下根本不需要 BEGIN 块。尽管如此,这个问题仍然是一个有趣的练习。
  • @Zaid 是的,没错。在我的答案中找到解决方案,我真的很开心!
【解决方案2】:

您可以使用perl -pe ... &lt; file 而不是perl -pe ... file。在这种情况下,如果文件不存在,甚至没有调用 perl,shell 就会抱怨。但是这个不能和-i开关一起使用。

或者由于您想使用-i 开关,您可以在使用之前检查文件是否可写。并不是说这会检查 qux 是否既是文件又是可写的,因为只有其中之一是不够的(也许还需要检查可读性)。

[ -f qux ] && [ -w qux ] && perl -pe ... -i qux

【讨论】:

  • 然而,这确实改变了 Perl 的语义,因为输出将被写入 STDOUT 而不是就地修改文件。
  • @DaveSherohman:你说得对,我没有注意到-i 开关。我添加了另一种解决问题的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-11
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多