Wenn es Ihrem Befehl egal ist, wie schnell Sie ihm Eingaben geben, und Sie nicht wirklich interagieren müssen damit können Sie ein Heredoc verwenden.
Beispiel:
#!/bin/bash
prog <<EOD
cmdx
save filex
cmdy
save filey
q
EOD
Wenn Sie eine Verzweigung basierend auf der Ausgabe des Programms benötigen oder wenn Ihr Programm überhaupt empfindlich auf das Timing Ihrer Befehle reagiert, dann ist Expect genau das, was Sie wollen.
Ich empfehle Ihnen, Expect zu verwenden. Dieses Tool wurde entwickelt, um interaktive Shell-Anwendungen zu automatisieren.
Wo Not ist, ist auch ein Weg! Ich denke, dass es eine gute Bash-Lektion ist, um zu sehen, wie Prozessmanagement und IPC funktionieren. Die beste Lösung ist natürlich Erwarten. Aber der wahre Grund ist, dass Pipes knifflig sein können und viele Befehle darauf ausgelegt sind, auf Daten zu warten, was bedeutet, dass der Prozess aus Gründen, die schwer vorhersehbar sind, zu einem Zombie wird. Aber zu erfahren, wie und warum, erinnert uns daran, was unter der Haube vor sich geht.
Wenn zwei Prozesse miteinander kommunizieren, besteht die Gefahr, dass einer oder beide versuchen, Daten zu lesen, die niemals ankommen werden. Die Einsatzregeln müssen glasklar sein. Dinge wie CRLF und Zeichenkodierung können die Party ruinieren. Glücklicherweise sind zwei enge Partner wie ein Bash-Skript und sein untergeordneter Prozess relativ einfach in Einklang zu bringen. Was am leichtesten zu übersehen ist, ist, dass bash für fast alles, was es tut, einen untergeordneten Prozess startet. Wenn Sie es mit Bash zum Laufen bringen können, wissen Sie genau, was Sie tun.
Der Punkt ist, dass wir mit einem anderen Prozess sprechen wollen. Hier ist ein Server:
# 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
Nun, das Skript, das hoffentlich die Magie ausübt.
# 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
Beachten Sie, dass wir die SMTP-Befehle nicht einfach auf dem Server ausgeben. Wir überprüfen jeden Antwortcode, um sicherzustellen, dass alles in Ordnung ist. In diesem Fall sind die Dinge nicht in Ordnung und das Skript bricht ab.