3

我正在编写一个 Perl 脚本,它应该在 shell 中执行命令并解析它们的输出。作为一个shell,我打算使用csh。我从这个开始

my $out = `cmd`

但它没有捕获我也需要的 STDERR。使用输出重定向运行 sh 什么都不做

my $out = `sh -c "cmd 2>&1"`

仍然只捕获 STDOUT,而不是 STDERR。

即使重定向到 csh 中的文件对我也不起作用

tcsh$ cmd >& logfile.log

仍然只捕获 STDOUT %)

我要执行的命令实际上是 sh 脚本,该脚本中的一些命令打印到 STDERR 中,我想捕获该输出。如果我执行sh -c "cmd 2>/dev/null"STDERR 实际上转到 /dev/null 并且只有 STDOUT 打印在终端中。

谁能帮我解决这个问题?

4

5 回答 5

2

我相信有些事情你没有告诉我们。你在cygwin吗?还是窗户?你有设置PERL5SHELL环境变量吗?

有些事情你没有告诉我们,因为这两个平台都可以在我可以轻松测试的五个平台上正常工作:

% perl -le '$out = `sh -c "grep missing /dev/nowhere 2>&1" | cat -n`; chomp $out; print "got <<<$out>>>"'
got <<<     1   grep: /dev/nowhere: No such file or directory>>>

但到目前为止,没有理由显式调用sh (1) 进行炮击。这是因为 Perl总是调用sh (1) 来处理所有的反引号、管道打开和system()脱壳:

% perl -le '$out = `grep missing /dev/nowhere 2>&1 | cat -n`; chomp $out; print "got <<<$out>>>"'
got <<<     1   grep: /dev/nowhere: No such file or directory>>>

我能想到的唯一例外发生在非 Unix 系统上,因为它们没有/bin/sh,所以定义了其他东西。

但是在任何情况下,简单的外壳都不会在您背后调用tcsh (1)。您必须认真破解perl (1) 源代码才能做到这一点。我也很怀疑您是否可以(轻松)破解二进制文件,因为字符串"/bin/tcsh"将比 长,而且无论如何"/bin/sh"都不会经常在/bin/中找到它。

即使从 shell 也无法使 stderr 重定向工作,这说明正在发生一些非常奇怪的事情。我认为我们需要更多信息。

于 2011-04-21T03:16:24.103 回答
1

我真的没有时间像往常一样模拟一个示例,甚至没有测试一个示例。我在想你可以试试看Capture::Tiny是否有帮助。

于 2011-07-24T15:49:56.737 回答
1

您说cmd >& logfile.log在 tcsh 中运行命令仅将 cmd 的标准输出发送到日志文件,而不是其标准错误。那没有意义。

尝试用以下脚本替换 cmd:

#!/bin/sh

echo stdout
echo STDERR 1>&2

“stdout”和“STDERR”都应该出现在 logfile.log 中。

如果是这样,那么也许您的“cmd”正在做一些奇怪的事情。我最好的猜测是 cmd 正在写入 /dev/tty,而不是 stdout 或 stderr;这不会受到重定向的影响。

要了解我的意思,请将此行添加到上面的脚本中:

echo tty > /dev/tty
于 2011-07-23T21:55:27.647 回答
1

在这里,您正在捕获 的 STDOUT sh,而不是 的 STDERR cmd

my $out = `sh -c "cmd 2>&1"`;

可以cmd直接跑吗?

my $out = `cmd 2>&1`;
于 2011-04-19T09:02:15.500 回答
1
  • 反引号捕获 STDOUT 而不是 STDERR。
  • system会将 stdout 和 stderr 转储到其父级的设置中。
  • 如果你想捕获STDERR,你需要类似的东西IPC::Open3

与open2()非常相似,open3()生成给定的 $cmd 并连接 CHLD_OUT 以从子级读取,CHLD_IN 用于写入子级,CHLD_ERR 用于错误。如果 CHLD_ERR 为假,

于 2011-04-19T12:14:56.840 回答