2010-09-28 94 views
1

我有一個可怕的嵌套的腳本結構我維持從用戶輸入的鍵盤週期性地,我想寫一個腳本,將自動輸入。本質上,該腳本結構看起來像這樣:如何從通過csh腳本調用的perl腳本中恢復STDIN?

  • cmd1.csh需要輸入的3行和 然後調用cmd2.csh,然後退出 通常
  • cmd2.csh呼叫cmd3.pl兩次 然後採取1行輸入,則 正常退出
  • cmd3.pl需要輸入1行 並正常退出。

不幸的是,我永遠不能改變任何這些腳本的,所以我能做些什麼必須做圍繞整個腳本鏈的包裝。

我已經試過以下perl腳本的幾個變化,但也許我只是不打引號的神奇組合和逃逸:

$cmd = "echo 'a\\ 
b\\ 
c\\ 
d\\ 
e\\ 
f' | ~/pltest/cmd1.csh"; 

system_tcsh 

sub system_tcsh 
{ 
    @args = ("tcsh", "-c", shift); 
    return system(@args); 
} 

的問題似乎是,一旦cmd3.pl是調用一次,d被讀取,第二次調用cmd3.pl或者通過cmd2.csh讀取更多輸入。將多個讀取放入cmd3.pl中可以正常工作,並且更多的項目將從STDIN中讀取,但是一旦第一次調用cmd3.pl完成,STDIN就會爲空(或處於某種不可用狀態)。

當perl腳本返回時,STDIN會發生什麼情況,並且有什麼方法使用perl或其他方法來模擬這種輸入?

在此先感謝。

回答

0

會發生什麼,如果你這樣做:如果不工作,你可以組織你的Perl腳本圍繞預取輸入,將其保存到臨時文件,然後做上述cat /path/to/tempfile | /path/to/cmd1.csh

echo 'a\ 
b\ 
c\ 
d\ 
e\ 
f' > tmpfile 
cat tmpfile | ~/pltest/cmd1.csh 

1

首先,我會使用Expect來編寫腳本輸入,它可能更可靠,並且在大多數Unix系統上都可用。

除了這個,根據你的echo版本,許多人都允許在引用字符串中使用「\ n」,儘管這在功能上應該是相同的。喜歡的東西:

$cmd = '/bin/echo -e "a\nb\nc\nd\ne\nf" | ~/pltest/cmd1.csh' 

(此作品在我的Linux機器.. man echo看到你的本地版本是可以勝任的。)

但是,實際上並沒有在尋找如何用Perl腳本讀取輸入,它的很難猜測輸出的確切位置,這當然是一個非常複雜的情況。

3

我創造了條件重現該問題,但一切都進展順利:

caller.pl:

#! /usr/bin/perl 

$cmd = "echo 'a\\ 
b\\ 
c\\ 
d\\ 
e\\ 
f' | ~/doc/Answers/src/pltest/cmd1.csh"; 

sub system_tcsh 
{ 
    @args = ("tcsh", "-c", $cmd); 
    return system(@args); 
} 

system_tcsh 

CMD1。CSH:

#! /bin/csh 
echo "${0}(cmd1) $argv[*]" 
set line1 = $< 
set line2 = $< 
set line3 = $< 
setenv lineno 3 
echo "cmd1: read: $line1 $line2 $line3" 
./cmd2.csh 

cmd2.csh:

#! /bin/csh 
echo " ${0}(cmd2) $argv[*] now running..." 
./cmd3.csh 
./cmd3.csh 

set line6 = $< 

echo " ${0}: Read: $line6" 

cmd3.csh:

#! /bin/csh 
# cmd3 
set line = $< 
echo "  ${0}: Read: '$line'" 

試運行:

[email protected] ~/doc/Answers/src/pltest $ ./caller.pl 
/export/home/frayser/doc/Answers/src/pltest/cmd1.csh(cmd1) 
cmd1: read: a b c 
    ./cmd2.csh(cmd2) now running... 
     ./cmd3.csh: Read: 'd' 
     ./cmd3.csh: Read: 'e' 
    ./cmd2.csh: Read: f 

也許你可以修改此重新創建的麻煩,或者用它來實現你的解決方案。

-

UPDATE
這是再現Perl的標準輸入問題的最新情況,並提供了一個解決它。

用Perl版本更換CMD3給人的報道,有問題的結果是:

cmd3.pl替換cmd3.csh:

#! /usr/bin/perl 
# cmd3 

$_=<STDIN>; 
chomp(); 
print "  $0: Read: '$_'\n"; 

結果:使用cmd3.pl。在讀取「d」之後,不再有輸入可用。

./caller.pl  
./cmd1.csh(cmd1) 
cmd1: read: a b c 
    ./cmd2.csh(cmd2) now running... 
     ./cmd3.pl: Read: 'd' 
     ./cmd3.pl: Read: '' 
    ./cmd2.csh: Read: 

爲了解決這個問題,CMD2更改爲只發送1線CMD3。所述line(1)命令輕易做到這一點:

#! /bin/csh 
echo " ${0}(cmd2) $argv[*] now running..." 
line | ./cmd3.pl 
line | ./cmd3.pl 

set line6 = $< 

echo " ${0}: Read: $line6" 

這是cmd2.csh優化,以避免執行命令的額外開銷。

#! /bin/csh 
echo " ${0}(cmd2) $argv[*] now running..." 
set x = $< 
echo $x | ./cmd3.pl 

set y = $< 
echo $y | ./cmd3.pl 

set line6 = $< 

echo " ${0}: Read: $line6" 

這裏是更新cmd2.csh輸出。使用Perl的功能與使用csh作爲最終腳本時的功能相同:沒有丟失stdin。

./cmd1.csh(cmd1) 
cmd1: read: a b c 
    ./cmd2.csh(cmd2) now running... 
     ./cmd3.pl: Read: 'd' 
     ./cmd3.pl: Read: 'e' 
    ./cmd2.csh: Read: f 
+0

[測試的binmode修復](http://stackoverflow.com/questions/3809357/how-do-i-recover-stdin-from-a-perl-script-that-was-called-from-a- CSH-腳本/ 3865528#3865528) 設置'binmode標準輸入, 「UNIX」'在* cmd3.pl *(並且沒有其他的變化)已經被驗證爲一個簡單的解決方案。 – frayser 2010-10-26 09:42:22

0

@just喬恩:不幸的是,期望的是不提供給我,我試圖找到我(因爲我們的請求過程是不完全的權宜之計)的工具的方法。不過謝謝你的迴應! perl腳本正在執行一個,或者兩個似乎都不能正常工作。

@ user268396:這似乎也不起作用,並且我會想象它是功能等同物,因爲管道將輸入強制輸入到STDIN,而不管數據來自何處。

@Frayser:你試過第三個腳本(cmd3.csh)作爲perl腳本嗎?這就是我的問題所涉及的問題。

+0

只是注意到你的答案。哇!隨着在Perl * CMD3 *,讀一次之後,沒有任何其他的命令可以得到更多的投入,甚至沒有* CMD3下一個Perl的調用*。如果我找到解決方案,我會發布。 – frayser 2010-10-24 09:56:32

+0

cmd2.csh必須被調整,以使得它僅提供一個行到的Perl(* cmd3.pl *):'設置艾琳= $ <;回聲「$ aline」| 。/ cmd3.pl'希望腳本可以修改爲讀1,然後只回聲1行到Perl;這解決了測試用例中的問題。 – frayser 2010-10-24 10:36:24

0

This answer about greedy perl stdin from Greg Bacon似乎是解決這個問題的方法。當然,這意味着我必須更改最內層的perl腳本,但如果我可以獲得更改權限,那麼這是迄今爲止最好的解決方案。這不是最穩健的解決方案 - 可能使用期望下午是最好的,但除此之外,這應該工作。