2011-04-19 48 views
3

我正在編寫一個Perl腳本,它應該在shell中執行命令並解析它們的輸出。作爲shell我打算使用csh。我已經開始這在重定向csh中的stderr時遇到麻煩

my $out = `cmd` 

但它不捕獲STDERR,我也需要。使用輸出重定向運行sh不會產生任何效果

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

仍然僅捕獲STDOUT,而不捕獲STDERR。

即使重定向在csh到文件對我來說不起作用

tcsh$ cmd >& logfile.log 

仍然捕捉STDOUT只%)

我想執行的命令是actuallty sh腳本,並在此的一些命令腳本打印到STDERR中,我想捕獲該輸出。如果我執行sh -c "cmd 2>/dev/null" STDERR實際上轉到/ dev/null,並且只有STDOUT被打印在終端中。

任何人都可以幫助我嗎?

+0

我試過運行sh shell並執行'cmd 2> logfile.log',但即使在這種情況下'logfile.log'也是空的。我懷疑tcsh不是這裏的主要問題 – mrvn 2011-04-19 11:23:47

回答

1

在這裏,您捕獲的sh標準輸出,這是不是cmd的STDERR:

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

可你只是直接運行cmd

my $out = `cmd 2>&1`; 
+0

不會在csh shell中運行cmd嗎?如果是這樣,csh不支持'2>&1'語法 – mrvn 2011-04-19 09:08:06

+0

cmd 2>&1 1>/dev/null應該這樣做 - 只是STDERR而不是別的 – Ingo 2011-04-19 09:08:29

+0

我還認爲'cmd 2>&1'應該重定向' cmd'到'sh'的STDOUT,而不是由perl捕獲。不是這樣嗎? – mrvn 2011-04-19 09:10:15

1
  • 後引號捕捉STDOUT STDERR沒有。
  • system會將stdout和stderr轉儲到其父設備。
  • 如果你想捕獲 STDERR,你需要像IPC::Open3

極其相似open2()open3()派生給定的$ cmd並從孩子讀,CHLD_IN用於寫入連接CHLD_OUT孩子和CHLD_ERR錯誤。如果CHLD_ERR爲假,

+0

與經常問到的問題非常相似,perldoc -q stderr」如何從外部命令捕獲STDERR?「 :-) – tadmc 2011-04-19 13:09:41

+0

@tadmc,我同意。 – Axeman 2011-04-19 13:34:44

+0

這是錯誤的。 '2>&1'就足夠了。 – tchrist 2011-04-21 03:05:15

1

我遇到了同樣的問題。在進行一些研究之後,我遇到了這個帖子:Capture stderr as well as stdout from a tcs。在這篇文章的底部,作者提出了他的解決方法,這也符合我的要求。我想你可以試試看。它可以很好地合併stderr和stdout的輸出。

+0

他不打電話給tcsh。 – tchrist 2011-04-21 03:07:03

1

我相信有些東西你沒有告訴我們。你在cygwin嗎?還是Windows?你有一個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)。你必須認真地攻擊源,才能實現這一目標。我相當懷疑你可以(容易地)破解二進制文件,因爲字符串"/bin/tcsh"將比"/bin/sh"更長,並且在/bin/中也不會經常發現。

你甚至不能從shell中得到stderr重定向工作,這說明有些奇怪的事情正在發生。我認爲我們需要更多信息。

+0

你好@tchrist,我在Linux,SuSE Desktop 11上。我剛剛發現STDERR和tcsh在這裏沒有關係......你的兩個例子工作正常。但是如果我把'cmd'而不是'grep' - 它不打印任何東西。所以'cmd'似乎將其輸出放入STDERR或STDOUT中。但是在哪裏?/dev/tty可能? – mrvn 2011-04-21 14:08:04

+0

@marvin:我想這是可能的。您可以通過在cron(1)作業中運行找到它。如果它正在寫入/ dev/tty,它仍然可以捕獲它,但是這樣做會讓人感到痛苦。 – tchrist 2011-04-21 14:37:30

1

你說在tcsh中運行命令cmd >& logfile.log只會將cmd的stdout發送到日誌文件,而不是它的stderr。這沒有意義。

嘗試用下面的腳本替換CMD:

#!/bin/sh 

echo stdout 
echo STDERR 1>&2 

兩個 「標準輸出」 和 「STDERR」 應該LOGFILE.LOG顯示出來。

如果是這樣,那麼也許你的「CMD」做了一些奇怪的事情。我最好的猜測是,cmd正在寫入/ dev/tty,而不是stdout或stderr;這不會受到重定向的影響。

要明白我的意思是,這行添加到上面的腳本:

echo tty > /dev/tty 
1

我真的沒有時間去嘲笑了一個例子,因爲我通常會,甚至也不是測試一個。我想你可能會嘗試使用Capture::Tiny來查看是否有幫助。