Можно ли заставить скрипт оболочки bash взаимодействовать с другой программой командной строки? - PullRequest
8 голосов
/ 10 августа 2010

Я использую интерактивную программу командной строки в терминале Linux с оболочкой bash.У меня есть определенная последовательность команд, которую я ввожу в программу оболочки.Программа записывает свой вывод в стандартный вывод.Одной из этих команд является команда «save», которая записывает вывод предыдущей команды, которая была выполнена, в файл на диск.

Типичный цикл:

$prog
$$cmdx
$$<some output>
$$save <filename>
$$cmdy
$$<again, some output>
$$save <filename>
$$q
$<back to bash shell>
  • $ - это приглашение bash
  • $$ - это приглашениеподсказка программы
  • q - это команда выхода для prog
  • prog такова, что она добавляет выходные данные предыдущегокоманда имя файла

Как я могу автоматизировать этот процесс?Я хотел бы написать сценарий оболочки, который может запустить эту программу и циклически проходить по шагам, передавая ей команды одну за другой и затем выходя из нее.Я надеюсь, что команда save работает правильно.

Ответы [ 6 ]

15 голосов
/ 10 августа 2010

Если вашей команде все равно, как быстро вы вводите ее, и вам не нужно взаимодействовать с ней , тогда вы можете использовать heredoc.

Пример:

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

Если вам нужно ветвление на основе выходных данных программы или если ваша программа вообще чувствительна к времени выполнения ваших команд, тогда Expect - это то, что вам нужно.

11 голосов
/ 10 августа 2010

Я рекомендую вам использовать Ожидайте . Этот инструмент предназначен для автоматизации приложений интерактивной оболочки.

6 голосов
/ 28 августа 2014

Там, где есть необходимость, есть способ!Я думаю, что это хороший урок для bash, чтобы увидеть, как работает управление процессами и ipc.Лучшее решение, конечно, Expect.Но настоящая причина в том, что каналы могут быть хитрыми, и многие команды предназначены для ожидания данных, а это означает, что процесс станет зомби по причинам, которые трудно предсказать.Но изучение того, как и почему напоминает нам о том, что происходит под капотом.

Когда в процессе участвуют два процесса, существует опасность того, что один или оба попытаются прочитать данные, которые никогда не поступят.Правила помолвки должны быть кристально чистыми.Такие вещи, как 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 на сервере.Мы проверяем каждый код ответа, чтобы убедиться, что все в порядке.В этом случае все будет не в порядке, и скрипт будет освобожден.

2 голосов
/ 10 августа 2010

Я использую Expect для взаимодействия с оболочкой для резервного копирования коммутатора и маршрутизатора.Bash-скрипт вызывает ожидаемый скрипт с правильными переменными.

for i in;do wait_script.sh $ i;выход

Это будет ssh для каждого блока, запуска команд резервного копирования, копирования соответствующих файлов и перехода к следующему блоку.

1 голос
/ 10 августа 2010

Для простых случаев использования вы можете использовать комбинацию subshell, echo и sleep:

# 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 
0 голосов
/ 10 августа 2010
echo "cmdx\nsave\n...etc..." | prog

..?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...