如何在 telnet 会话中运行脚本?

如何在 telnet 会话中运行脚本?

我想使用 telnet 连接到远程主机,没有用户名/密码验证,只是

telnet remotehost

然后我需要输入一些命令进行初始化

然后我需要重复以下命令:

cmd argument

参数是从本地文件读取的,这个文件中有很多行,每一行都是一个参数,运行一个“cmd 参数”后,远程主机将输出一些结果,它可能输出一行字符串“OK”,或者输出多行,其中一行带有字符串“ERROR”,我需要根据结果做一些事情。

基本上,脚本如下:

initialization_cmd  #some initial comands
while read line
do    
  cmd $line
  #here the remote host will output results, how can I put the results into a variable?
  # here I want to judge the results, like
  if $results contain "OK";then
       echo $line >>good_result_log
  else
       echo $line >> bad_result_log
  fi     
done < local_file

 the good_result_log and bad_result_log are local files

这可能吗?谢谢!

注意:我无法控制 B,我只能在 B 上运行初始命令和 cmd $line

答案1

如果您手动启动 telnet,这实际上不是您可以做的事情 - 但是,我个人会编辑您的脚本文件并从其中启动 telnet,将来自 telnet 的输出行作为 bash 中的输入进行处理。

我实际上无法举例说明,因为我只从 Windows 脚本而不是 Bash 中完成此操作,但我知道这将轻松实现您的要求。

答案2

bash确实不是适合这项工作的工具。

解决此类问题的典型工具是预计,它基本上允许您编写与诸如、等程序的交互脚本telnetftp我确信股票 Expect 发行版包含一些可以直接适应您情况的示例。

如果你更喜欢 Python 语言(而不是 Expect 使用的 Tcl 语言),可以考虑期望反而。

答案3

是的,这确实是你我觉得是的。请参阅下面的代码示例。我确实对你描述的情况感到疑惑,但很久以前 --- 这似乎是一个经典问题。现在,因为我已经bash好几年没碰了,我真的需要重新开始${shape}并赚取 $$ 积分,所以我把这当作一个小练习。

您将需要两个文件,均包含在下面:(session_driver.sh非常简化的模拟expect)和您自己的脚本形式的控制器逻辑,controller_script.sh以驱动您的会话。驱动程序适用于 telnet(使用 netcat 客户端)和 ssh。以下是两个连接示例,第一个是在 ssh 模式下(SSH=1)

NAME=root SSH=1 HOST=my-nas ./session_driver.sh controller_script.sh

my-nas这会将您以用户身份登录到网络连接存储设备,root以便使用 ssh 进行一些随机操作。不过,您必须手动提供密码。以下是使用默认 telnet 模式的 telnet 调用:

NAME=root PWORD='123' HOST=my-nas ./session_driver.sh controller_script.sh

在这里您指定密码“123”,PWORD因此 telnet 会话是 100% 自动化的。

该脚本在 Linux 下测试。

会话驱动程序

/bin/bash #!/bin/bash
#
# BASH 远程会话驱动程序
#——用于脚本 telnet 或 rsh。
#
# 参考:http://superuser.com/questions/521716/how-to-run-scripts-within-a-telnet-session
#
使用情况=$(cat<<END
用法:session_driver.sh CONTROLLER_SCRIPT

其中 CONTROLLER_SCRIPT 是一个 bash 源文件,它定义了一个名为
“控制器脚本”。

环境变量必须传递值,如以下两个示例所示。

(a)通过 nc(netcat)连接到 telnet 服务器(默认):

    $ HOST=mybank.com NAME=me PWORD=1234 session_driver.sh milk_account.sh

    密码PWORD可以省略。

(b)通过 ssh 连接到安全 shell 服务器:

    $ SSH=1 HOST=mybank.com NAME=me session_driver.sh milk_account.sh

    在这种情况下,请不要使用 PWORD。如果需要,ssh 会提示您。

使用函数 echo_stderr、read_one_line_response 和 read_some_lines_response
在您的 CONTROLLER_SCRIPT 中。处理慢速时调整 MULTIPLE_LINES_TIMEOUT
回应。
结尾

script_name="SESSION_DRIVER"

# 参数

如果 [[ -z "$1" ]] || (echo "$1" | grep -qE "^[-][-]?[h|H]"); 然后
    回显“$USAGE”
    出口 1

controller_script_path=$1

# 可覆盖的参数

HOST=${HOST:?指定要连接到哪里!}
NAME=${NAME:?指定用户名}
PWORD=${PWORD:-} # 仅限 telnet 模式
MULTIPLE_LINES_TIMEOUT=1 # 等待每一行输出的时间
                          # (很快)
SSH=${SSH:-0} # 默认使用 telnet                                       

# 管道

tmpdir=$(mktemp -d) # 放置管道设备的安全位置
trap 'rm -rf "$tmpdir"; echo "$script_name: all done"' EXIT # 摆脱位置
                                                              # 终止时

# 我们需要一个后门 fd,以便我们可以从服务器内部喷出输出
# 控制器到外部。
exec 3>&2 # 将 fd3 指向 fd2 的副本 (stderr)

# 我们需要一个额外的管道来将服务器的输出传输回
# 服务器控制器。命名管道就可以了。这非常便于携带。
mkfifo ${tmpdir}/输出


# 设置连接命令和控制器脚本

# 确定模式。
如果 [ "$SSH" == 1 ]; 然后
    cmd="ssh -t -t $HOST -l $NAME" # -t(两次)强制 tty 模拟
别的
    cmd="nc -t $HOST 23"

# 读取控制器脚本。
如果 [[ !-f "$controller_script_path" ]]; 然后
    echo“$script_name:脚本\“$controller_script_path\”未找到
    出口 1
源“$controller_script_path”
如果!(声明-f controller_script> / dev / null); 然后
    echo“$script_name:脚本未定义函数‘controller_script’”
    出口 1

# 服务器控制器辅助功能

# 通过后门管道(fd3)发送调试信息。
函数 echo_stderr(){
    回显“$1”>&3
}

# 读取预期的一行输出并将其转发到标准输出。
函数 read_one_line_response () {
    本地线路
     # 按照 telnet 回显的方式吃掉命令行。
    读取 < ${tmpdir}/output
    # 现在获取响应行。
    读取行 < ${tmpdir}/output
    echo $line | tr -d '\r' # 去掉烦人的回车符
}

# 读取任意数量的输出行,只要它们出现得足够多
# 关闭(在 MULTIPLE_LINES_TIMEOUT 秒内);全部通过管道传输到标准输出。
函数 read_some_lines_response () {
    本地线路
    读取 < ${tmpdir}/output
    当读取 -t ${MULTIPLE_LINES_TIMEOUT} 行 < ${tmpdir}/output 时;执行
        回显 $line | tr -d '\r'  
    完毕    
}

函数密码交互(){
    如果 [[ -n "$NAME" && "$SSH" == 0 ]]; 然后
        # 读取到 ':' 为止的字符。我们不会得到完整的一行。希望
        # 我们将看到“登录”。
        while true; 执行
            读取-d“:”行<${tmpdir}/output;
            (echo $line | grep "login" > /dev/null)&&break;
        完毕
        回显“$NAME”
        读取 < ${tmpdir}/output
        回显“$PWORD”
        读取 < ${tmpdir}/output
    别的
        read_some_lines_response > /dev/null        
}

# 将命令推送到标准输出上的服务器。从以下位置读取服务器的输出
# 管道。并将日志信息推送到 fd3 上。
函数控制器(){

    密码交互

    controller_script # 调用作为命令行参数提供的脚本
}

# 焊接在一起

# 控制器的标准输出作为命令发送到服务器。
# 服务器的标准输出和错误都转到标准输出。但由于
# 'tee',控制器还能够读取服务器的标准输出和
# 通过命名管道的错误。注意由控制器生成的后门输出
# 在 fd3 上,通过上面的“exec”文件重定向转到管道线的 stderr。
控制器 | ${cmd} 2>&1 | tee ${tmpdir}/output

控制器脚本

# session_driver 的示例控制器脚本,一种执行“expect”的 bash 方式
# 用于驱动远程 telnet 或 ssh 会话。此脚本由
#session_driver.sh 脚本。

# 注意我们在源脚本中定义的内容的使用:
#-echo_stderr 通过后门发送日志信息;
#-read_one_line_response,阻塞函数,获取预期输出
# 线;
#-read_some_lines_response,暂时阻塞函数,获取几个
# 预期输出行数;以及
#-${tmpdir} 供临时使用。

MAX_ITERATIONS=10 # 这样我们就可以限制示例

# 列出服务器的初始命令
cat > ${tmpdir}/myinitcommands <<- EOF
    回声你好
    不起作用
    密码
末梢血

函数控制器脚本(){
    本地响应命令行 n
   # 播放命令列表
    当读取 cmdline 时;执行
        echo_stderr "CONTROLLER_SCRIPT:执行:$cmdline"  
        回显“$cmdline”
        read_some_lines_response > /dev/null
    完成 < ${tmpdir}/myinitcommands
    echo_stderr“CONTROLLER_SCRIPT:完成初始命令”  
    # 多次进行愚蠢的互动
    # 我们在这里仔细阅读对每个发出的命令的一行响应,并
    # 做出相应反应:如果挂钟的秒数是偶数,那么我们
    # 要求服务器向我们提供其当前目录列表。
    对于((n=0;n<$MAX_ITERATIONS;n++));执行
        # 让服务器调用日期函数来获取当前的秒数
        # 分钟。
        echo_stderr "CONTROLLER_SCRIPT: 执行:\"date +f %S\"" # 记录命令
        echo "sleep 2; date +%S" # 执行此操作!
        # 读取一行输出。一般来说,需要小心
        # 关于读取多少输出:读取正在阻塞!
        响应=$(read_one_line_response)
        如果 ((${response#?} % 2 == 0)); 然后
            echo_stderr "CONTROLLER_SCRIPT: even: $response seconds" # 日志事件
            echo "ls /" # 在服务器上执行
            read_some_lines_response > /dev/null # 这里不需要它             
        别的
            echo_stderr "CONTROLLER_SCRIPT: odd: $response seconds" # 日志事件
        睡眠 1
    完毕
    echo exit #终止远程会话
}

相关内容