使用 bash 脚本自动化远程登录会话

Posted

技术标签:

【中文标题】使用 bash 脚本自动化远程登录会话【英文标题】:Automating telnet session using bash scripts 【发布时间】:2011-10-24 04:43:27 【问题描述】:

我正在使用 Bash 脚本自动化一些与telnet 相关的任务。 一旦自动化,用户将不再与telnet 进行交互(即完全自动化)

脚本看起来像这样:

# execute some commands on the local system
# access a remote system with an IP address: 10.1.1.1 (for example)

telnet 10.1.1.1

# execute some commands on the remote system
# log all the activity (in a file) on the Local system
# exit telnet
# continue on with executing the rest of the script.

我在这里面临两个问题:

    如何通过脚本在远程系统上执行命令(无需人工干预)?

    根据我对一些测试代码的经验,我能够推断当telnet 10.1.1.1 被执行时,telnet 进入一个交互式会话,并且脚本中的后续代码行在本地系统上执行。如何在远程系统而不是本地系统上运行代码行?

    我无法获取本地系统上telnet 会话中活动的日志文件。我使用的标准输出重定向在远程系统上进行了复制(我不想执行复制操作将日志复制到本地系统)。我怎样才能实现这个功能?

【问题讨论】:

【参考方案1】:

编写一个expect 脚本。

这是一个例子:

#!/usr/bin/expect

#If it all goes pear shaped the script will timeout after 20 seconds.
set timeout 20
#First argument is assigned to the variable name
set name [lindex $argv 0]
#Second argument is assigned to the variable user
set user [lindex $argv 1]
#Third argument is assigned to the variable password
set password [lindex $argv 2]
#This spawns the telnet program and connects it to the variable name
spawn telnet $name 
#The script expects login
expect "login:" 
#The script sends the user variable
send "$user "
#The script expects Password
expect "Password:"
#The script sends the password variable
send "$password "
#This hands control of the keyboard over to you (Nice expect feature!)
interact

运行:

./myscript.expect name user password

【讨论】:

“期望”主要用于交互式会话。我想要的是一个自动化的非交互式会话。我面临的问题是我无法在远程系统上运行脚本(通过 telnet),因为 telnet 10.1.1.1 之后的所有行都在本地机器上执行,而不是在我的机器上执行访问。 正如 Thomas Telensky 指出的,根据您的需要,ssh 最终会更容易。但是 expect 可以是完全非交互式的。我假设您的意思是 telnet 之后的所有行都是您希望在远程计算机上执行的,在这种情况下,只需将它们作为发送命令添加到期望脚本并删除交互命令即可。但 ssh 更简单、更安全。 很公平。我将使用 expect 来完成这项任务。【参考方案2】:

为此目的使用 ssh。在不使用密码的情况下生成密钥并将其放置在远程机器上的 .authorized_keys 中。创建要远程运行的脚本,将其复制到另一台机器上,然后使用 ssh 远程运行它。

我多次使用这种方法并取得了巨大的成功。另请注意,它比 telnet 安全得多。

【讨论】:

ssh 肯定比telnet 更安全,但是有些IP 设备就是不提供ssh 服务,而是依赖telnet 协议来使用设备。 telnet(程序)可以用作任何(或更实际地)基于文本的客户端/服务器连接的客户端。它可以用于简单的测试,例如 HTTP 和 IMAP。 @Tomas 的建议是将 Telnet(远程登录服务)的使用替换为 SSH。虽然他的评论是真实的,但这可能不是 OP 所要求的。 Rob,telnet 确实可用于连接到任何端口,但请参阅 OPs 问题 - 在他的上下文中,他只想将 telnet 用于 login(引用:“在远程系统上执行一些命令”)。为此目的使用 telnet 是非常危险的。 这不是对使用他现有脚本专门说“自动化一些与 telnet 相关的任务”的问题的答案。【参考方案3】:

虽然我也建议使用 expect,但对于非交互式使用,普通的 shell 命令可能就足够了。 telnet 在标准输入上接受它的命令,所以你只需要通过heredoc 管道或写入命令:

telnet 10.1.1.1 <<EOF
remotecommand 1
remotecommand 2
EOF

(编辑:从 cmets 判断,远程命令需要一些时间来处理输入,或者早期的 SIGHUP 没有被 telnet 优雅地采用。在这些情况下,您可以尝试短在输入上睡觉:)

 echo "remotecommand 1"; echo "remotecommand 2"; sleep 1;  | telnet 10.1.1.1

在任何情况下,如果要进行互动或其他任何事情,请使用expect

【讨论】:

+1 sleep 像梦一样工作 ;-) 我还在两者之间添加了 | tee /dev/tty | 以在屏幕上进行完整会话;-) 就我而言,这是最有帮助的答案,但我必须添加echo -e "command\r"; 如何以非交互方式为 telnet 提供密码? echo "remotecommand 1"; echo "remotecommand 2"; sleep 1; | telnet 10.1.1.1 :这个例子符合我的要求。只想知道如果telnet失败我们如何添加错误检查并且shell脚本应该exit 1【参考方案4】:

tcpdumpwireshark 看看哪些命令会发送到服务器本身

试试这个

printf (printf "$username\r\n$password\r\nwhoami\r\nexit\r\n") | ncat $target 23

一些服务器需要延迟密码,因为它不会在堆栈上保存行

printf (printf "$username\r\n";sleep 1;printf "$password\r\nwhoami\r\nexit\r\n") | ncat $target 23**

【讨论】:

新奇不是粗鲁的借口。请参阅常见问题解答***.com/faq。 并不是侮辱,更像是......我不知道,道歉。我只是不断看到人们使用期望命令作为解决方案。我只是想让人们意识到有一个更好的解决方案来理解你想要完成的事情。 expect 命令并没有告诉你它是如何工作的,它只是一个不知道的解决方法。它比没有更令人困惑。如有疑问,请前往源头。如果源不可用,并且如果它是网络协议,tcpdump,wireshark,窥探数据包并遵循命令流,您应该能够将一些东西放在一起工作知识。 如果你这么说 - 我是一名 Mathematica 程序员,所以你的回答和评论的实质对我来说是个谜。但我并不是唯一一个将“白痴”这个词解释为故意侮辱的人。我认为您需要在该网站上多花点时间,看看人们在这里的行为如何。【参考方案5】:

在学习 HTTP 协议时经常使用 Telnet。我曾经将该脚本用作我的网络抓取工具的一部分:

echo "open www.example.com 80" 
sleep 2 
echo "GET /index.html HTTP/1.1" 
echo "Host: www.example.com" 
echo 
echo 
sleep 2

假设脚本的名称是 get-page.sh 那么:

get-page.sh | telnet

会给你一个html文件。

希望对某人有所帮助;)

【讨论】:

最有帮助的评论!这实际上使您可以通过将命令置于循环中来自动发送命令 另一个帮助帖子blog.tonycode.com/tech-stuff/http-notes/… 单行等效项: echo "GET / HTTP/1.1"; echo "Host: www.example.com"; echo; sleep 1; | telnet www.example.com 80。请注意,一开始不需要 sleep(除非您使用 open 命令),最后只需要一个空 echo 和 sleep 1 而不是 2。 但是如果你需要做HTTPS请求,你应该使用netcat,也称为ncat或nc: echo "GET / HTTP/1.1"; echo "Host: example.com"; echo; sleep 1; | ncat --ssl example.com 443 非常有帮助。这将在屏幕上获得输出。无论如何我可以等待来自 telnet 的已知字符串,然后运行我的下一个命令,而不是 sleep?【参考方案6】:

您可以使用期望脚本来代替 bash。 下面的例子展示了如何连接到没有密码的嵌入式板

#!/usr/bin/expect

set ip "<ip>"

spawn "/bin/bash"
send "telnet $ip\r"
expect "'^]'."
send "\r"
expect "#"
sleep 2

send "ls\r"
expect "#"

sleep 2
send -- "^]\r"
expect "telnet>"
send  "quit\r"
expect eof

【讨论】:

【参考方案7】:

这对我有用..

我试图自动化多个需要用户名和密码的 telnet 登录。 telnet 会话需要无限期地在后台运行,因为我正在将来自不同服务器的日志保存到我的机器上。

telnet.sh 使用“expect”命令自动进行 telnet 登录。更多信息可以在这里找到:http://osix.net/modules/article/?id=30

telnet.sh

#!/usr/bin/expect
set timeout 20
set hostName [lindex $argv 0]
set userName [lindex $argv 1]
set password [lindex $argv 2]

spawn telnet $hostName

expect "User Access Verification"
expect "Username:"
send "$userName\r"
expect "Password:"
send "$password\r";
interact

sample_script.sh 用于通过运行 telnet.sh 为每个 telnet 会话创建一个后台进程。更多信息可以在代码的 cmets 部分找到。

sample_script.sh

#!/bin/bash
#start screen in detached mode with session-name 'default_session' 
screen -dmS default_session -t screen_name 
#save the generated logs in a log file 'abc.log' 
screen -S default_session -p screen_name -X stuff "script -f /tmp/abc.log $(printf \\r)"
#start the telnet session and generate logs
screen -S default_session -p screen_name -X stuff "expect telnet.sh hostname username password $(printf \\r)"
    使用 命令“屏幕-ls”。 读取 http://www.gnu.org/software/screen/manual/screen.html#Stuff阅读 有关屏幕及其选项的更多信息。 sample_script.sh 中的“-p”选项 预选并重新附加到特定窗口以通过以下方式发送命令 “-X”选项,否则会出现“未找到屏幕会话”错误。

【讨论】:

【参考方案8】:
#!/bin/bash
ping_count="4"
avg_max_limit="1500"
router="sagemcom-fast-2804-v2"
adress="192.168.1.1"
user="admin"
pass="admin"

VAR=$(
expect -c " 
        set timeout 3
        spawn telnet "$adress"
        expect \"Login:\" 
        send \"$user\n\"
        expect \"Password:\"
        send \"$pass\n\"
        expect \"commands.\"
        send \"ping ya.ru -c $ping_count\n\"
        set timeout 9
        expect \"transmitted\"
        send \"exit\"
        ")

count_ping=$(echo "$VAR" | grep packets | cut -c 1)
avg_ms=$(echo "$VAR" | grep round-trip | cut -d '/' -f 4 | cut -d '.' -f 1)

echo "1_____ping___$count_ping|||____$avg_ms"
echo "$VAR"

【讨论】:

【参考方案9】:

这里是如何在 bash shell/expect 中使用 telnet

#!/usr/bin/expect
# just do a chmod 755 one the script
# ./YOUR_SCRIPT_NAME.sh $YOUHOST $PORT
# if you get "Escape character is '^]'" as the output it means got connected otherwise it has failed

set ip [lindex $argv 0]
set port [lindex $argv 1]

set timeout 5
spawn telnet $ip $port
expect "'^]'."

【讨论】:

【参考方案10】:

以下对我有用... 把你想远程登录的所有IP都放在IP_sheet.txt中

while true
read a
do

    sleep 3
    echo df -kh
    sleep 3
    echo exit
 | telnet $a
done<IP_sheet.txt

【讨论】:

【参考方案11】:

获取 CISCO 服务器版本的脚本:

#!/bin/sh

servers='
192.168.34.1
192.168.34.3
192.168.34.2
192.168.34.3
'
user='cisco_login'
pass='cisco_password'

show_version() 
host=$1
expect << EOF
set timeout 20
set host $host
set user $user
set pass $pass
spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect -re ".*#"
send "show version\r"
expect -re ".*-More-.*"
send " "
expect -re ".*#"
send "exit\r"
EOF


for ip in $servers; do
  echo '---------------------------------------------'
  echo "$ip"
  show_version $ip | grep -A3 'SW Version'
done

【讨论】:

【参考方案12】:

这是一个适用于扩展程序列表的解决方案。这只需要 bash - 上面的一些答案需要 expect 并且您可能无法指望安装 expect。

#!/bin/bash

declare -a  Extenders=("192.168.1.48" "192.168.1.50" "192.168.1.51") 
# "192.168.1.52" "192.168.1.56" "192.168.1.58" "192.168.1.59" "192.168.1.143")
sleep 5
# Iterate the string array using for loop
for val in $Extenders[@]; do
    sleep 0.2; echo "root"; sleep 0.2; echo "ls"; sleep 0.2;   | telnet $val
done

【讨论】:

【参考方案13】:

@thiton 的 answer 很有帮助,但我想避免使用 sleep 命令。还有telnet没有退出交互模式,所以我的脚本卡住了。

我通过使用 curl 发送 telnet 命令(似乎在等待响应)并明确告诉 telnet 像这样退出来解决了这个问题:

curl telnet://10.1.1.1:23 <<EOF
remotecommand 1
remotecommand 2
quit
EOF

【讨论】:

远程服务器是否需要quitexit 或其他东西完全取决于另一端的内容。该命令被发送到远程服务器,而不是telnet 客户端本身(除了作为输出到另一端的输入)。也许您可以编辑以澄清这一点? @tripleee 谢谢,很高兴知道。当我在telnet 客户端中尝试telnet 时,我实际上很惊讶quit 没有使用^] 转义。我稍后会在答案中澄清这一点。您知道在使用telnet(或curl)时是否可以在脚本中退出客户端,而不依赖于服务器行为? 实际上,如果curl 遵循与传统telnet 相同的转义机制,我会感到非常惊讶,并且根据简短的实验,它似乎确实没有。 ***.com/questions/42347271/… 建议使用超时;该手册没有提到带外命令的任何内容。

以上是关于使用 bash 脚本自动化远程登录会话的主要内容,如果未能解决你的问题,请参考以下文章

远程登录 redis bash 脚本

分发系统介绍,expect脚本远程登录,expect脚本远程执行命令,expect脚本传递参数

6月份个人:修改Windows系统多人使用多账号同时远程登陆 并修改脚本自动生成每个用户登录日志。

使用sshpass和ssh实现无密码自动远程登录

如何在 bash 脚本中的流水线命令之间插入延迟。例如。猫文件 |远程登录 mail.domain.com 25

为 Telnet 会话创建脚本?