2010-08-10 37 views
7

我在運行bash shell的Linux終端中使用交互式命令行程序。我有一個確定的命令序列,我輸入到shell程序。該程序將其輸出寫入標準輸出。其中一個命令是'save'命令,它將運行的前一個命令的輸出寫入文件到磁盤。是否有可能使bash shell腳本與另一個命令行程序進行交互?

典型的循環是:

$prog 
$$cmdx 
$$<some output> 
$$save <filename> 
$$cmdy 
$$<again, some output> 
$$save <filename> 
$$q 
$<back to bash shell> 
  • $是bash提示符
  • $$是程序的提示
  • qPROG quit命令
  • PROG是這樣的,它附加上一個命令的輸出

我怎麼能自動完成這一過程?我想編寫一個可以啓動這個程序的shell腳本,並循環執行這些步驟,逐個給它提供命令,然後退出。我希望保存命令能正常工作。

回答

15

如果你的命令不關心你給它輸入的速度有多快,並且你不需要與它交互,那麼你可以使用heredoc。

例子:

#!/bin/bash 
prog <<EOD 
cmdx 
save filex 
cmdy 
save filey 
q 
EOD 

如果您需要根據程序的輸出分支,或者如果你的程序是在所有敏感到你的命令的時間,然後期望是你想要的。

+0

這符合我的目的。我不確定標準輸出的位置。 – rup 2010-08-12 10:37:21

0
echo "cmdx\nsave\n...etc..." | prog 

..?

9

我建議你使用Expect。該工具旨在自動化交互式shell應用程序。

1

對於簡單的用例,你可以使用子shell的組合,回聲&睡眠:

# in Terminal.app 
telnet localhost 25 
helo localhost 
ehlo localhost 
quit 

(sleep 5; echo "helo localhost"; sleep 5; echo "ehlo localhost"; sleep 5; echo quit) | 
    telnet localhost 25 
1

我用期待與外殼的交換機和路由器的備份互動。一個bash腳本用正確的變量調用expect腳本。

for i in;做expect_script.sh $ i;退出

這將ssh到每個框,運行備份命令,複製出適當的文件,然後移動到下一個框。

6

哪裏有需求,有辦法!我認爲這是一個很好的bash課程,可以看到 流程管理和ipc是如何工作的。當然,最好的解決方案是預期。 但真正的原因是管道可能會非常棘手,許多命令設計爲等待數據,這意味着該過程將成爲殭屍,因爲難以預測的原因。但是學習如何以及爲什麼會讓我們想起 正在發生什麼。

當兩個進程進行對話時,其中一個或兩個進程會嘗試讀取永遠不會到達的數據。交戰規則必須是清晰的 。像CRLF和字符編碼這樣的東西可能會殺死這個派對。 幸運的是,像bash腳本和它的子進程這樣的兩個關係密切的合作伙伴 相對容易保持一致。最容易遺漏的是bash是 幾乎爲它所做的每件事都啓動了一個子進程。如果你可以讓 與bash一起工作,你完全知道你在做什麼。

問題是我們想要與另一個進程交談。這裏是一個服務器:

# a really bad SMTP server 

# a hint at courtesy to the client 
shopt -s nocasematch 

echo "220 $HOSTNAME SMTP [$$]" 

while true 
do 
    read 
    [[ "$REPLY" =~ ^helo\ [^\ ] ]] && break 
    [[ "$REPLY" =~ ^quit ]] && echo "Later" && exit 
    echo 503 5.5.1 Nice guys say hello. 
done 

NAME=`echo "$REPLY" | sed -r -e 's/^helo //i'` 
echo 250 Hello there, $NAME 

while read 
do 
    [[ "$REPLY" =~ ^mail\ from: ]] && { echo 250 2.1.0 Good guess...; continue; } 
    [[ "$REPLY" =~ ^rcpt\ to: ]] && { echo 250 2.1.0 Keep trying...; continue; } 
    [[ "$REPLY" =~ ^quit ]] && { echo Later, $NAME; exit; } 
    echo 502 5.5.2 Please just QUIT 
done 

echo Pipe closed, exiting 

現在,腳本,希望做的魔術。

# Talk to a subprocess using named pipes 

rm -fr A B  # don't use old pipes 
mkfifo A B 

# server will listen to A and send to B 
./smtp.sh <A> B & 

# If we write to A, the pipe will be closed. 
# That doesn't happen when writing to a file handle. 
exec 3>A 

read < B 
echo "$REPLY" 

# send an email, so long as response codes look good 
while read L 
do 
    echo "> $L" 
    echo $L > A 
    read < B 
    echo $REPLY 
    [[ "$REPLY" =~ ^2 ]] || break 

done <<EOF 
HELO me 
MAIL FROM: me 
RCPT TO: you 
DATA 
Subject: Nothing 

Message 
. 
EOF 

# This is tricky, and the reason sane people use Expect. If we 
# send QUIT and then wait on B (ie. cat B) we may have trouble. 
# If the server exits, the "Later" response in the pipe might 
# disappear, leaving the cat command (and us) waiting for data. 
# So, let cat have our STDOUT and move on. 
cat B & 

# Now, we should wait for the cat process to get going before we 
# send the QUIT command. If we don't, the server will exit, the 
# pipe will empty and cat will miss its chance to show the 
# server's final words. 
echo -n > B  # also, 'sleep 1' will probably work. 

echo "> quit" 
echo "quit" > A 

# close the file handle 
exec 3>&- 

rm A B 

請注意,我們不是簡單地在服務器上轉儲SMTP命令。我們檢查 每個響應代碼,以確保事情是確定的。在這種情況下,事情不會是 行,腳本將保釋。

相關問題