www.91084.com

GVKun编程网logo

shell expect SSH 用法一例(shell expr)

16

针对shellexpectSSH用法一例和shellexpr这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展0SHELL训练营--day10_expect、083-使用shell和expec

针对shell expect SSH 用法一例shell expr这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展0 SHELL训练营--day10_expect、083-使用shell和expect一键批量分发SSH密钥脚本、bash – 如何将变量从shell脚本传递到expect脚本?、expect 实现类似 xshell 的脚本登录等相关知识,希望可以帮助到你。

本文目录一览:

shell expect SSH 用法一例(shell expr)

shell expect SSH 用法一例(shell expr)

本文重点解决两个问题:

  1. 获取 SSH 远程执行命令的返回状态
  2. expect 执行 SSH 时进程中不显示密码明文

先上 Shell 代码:

export IP CMD SSH_PWD
expect << ''END''
# 关闭输出
log_user 0
set timeout 30
# 从系统变量获取数据
set ip "$env(IP)"
set cmd "$env(CMD)"
set pwd "$env(SSH_PWD)"
spawn ssh root@$ip "$cmd"
expect {
    "(yes/no)?"                           {send "yes\r";exp_continue}
    # 忽略大小写
    -nocase "password:"                   {send "$pwd\r";exp_continue}
    # 登录成功,打开输出
    -nocase "authentication successful"   {log_user 1;exp_continue}
    # 登录失败
    -nocase "authentication fail"         {exit 222}
    -nocase "permission denied"           {exit 222}
    eof
}
puts $expect_out(buffer)
lassign [wait] pid spawnid os_error_flag value
# 系统错误
if {$os_error_flag == -1} {
    puts "os errno: $value"
} else {
    # 返回 CMD 执行结果
    exit $value
}
END
exitCode=$?
if [ $exitCode -eq 222 ]; then
    echo ''log error''
elif [ $exitCode -ne 0 ]; then
    echo ''cmd error''
fi

获取执行结果的关键在于【wait】方法的使用:

wait [args]

delays until a spawned process (or the current process if none is named) terminates.

wait normally returns a list of four integers. The first integer is the pid of the process that was waited upon. The second integer is the corresponding spawn id. The third integer is -1 if an operating system error occurred, or 0 otherwise. If the third integer was 0, the fourth integer is the status returned by the spawned process. If the third integer was -1, the fourth integer is the value of errno set by the operating system. The global variable errorCode is also set.

【wait】:延迟直到一个 spawn 进程结束。返回 4 个数值:

  1. expect 进程 pid
  2. spawn 线程 id
  3. OS 状态值(-1:系统错误,0:正常)
  4. spawn 命令返回值(OS 值为 -1 时返回 OS 错误代码,为 0 时返回 CMD 退出值)

参考:expect man、How to get the exit code of spawned process in expect shell script?

开头的两个问题都得到了解决:

  • 使用 wait 获取 SSH 远程执行命令的返回状态,登录失败也可以通过指定状态码(222)标识;
  • 使用 env 读取外部变量到 expect 变量中,从而 PS 不会显示 密码明文。

0 SHELL训练营--day10_expect

0 SHELL训练营--day10_expect

expect

expect 是一个免费的编程工具语言,对于交互的场合,实现自动和交互式任务进行通信,而无需人的干预。
expect 安装:yum install -y expect
expect 脚本定义:默认以“.expect” 为后缀。脚本语言在首行要指明语言工具:#!/usr/bin/expect
expect 由一系列expect-send对组成:expect等待输出中输出特定的字符,通常是一个提示符,然后send 发送特定的响应。

  • 变量定义

    expect通过 set 命令定义变量。
    变量来源有两种形式:

    1. set a 1 直接定义 变量和 值。
    2. set host [lindex $argv 0] 通过获取脚本传递过来的参数定义变量,实现交互。
  • spawn创建子进程

    expect 通过 spawn 创建一个执行program args命令的进程。它的stdin,stdout,stderr(标准输入,标准输出,标准错误输出)都连到Expect。
    如通过spawn创建一个SSH连接,并通过 expect捕捉stdout标准输出信息,再通过 send 向spawn生成的进程 输入 相关命令。

    #1登录示例
    #!/usr/bin/expect
    set use root
    set passwd 123456!
    set host 192.168.20.2
    spawn ssh [email protected]$host
    expect {
    "yes/no" { send "yes\r"}  # 遇到包含"yes/no"的标准输出信息时,通过send发送确认信息。
    "password:" { send "$passwd\r" }
    }
    expect "#*"  
    send "pwd\r"
  • 延时功能

    需要注意的是spawn是expect环境下,expect语言内部命令。它生成的进程执行完成后,会自动退出。
    通过spawn生成的进程,可通过send向远程的服务器传递命令,这个命令执行是远程主机生成的tty窗口执行,而不是在本地的spawn进程中执行。这两个进程,在命令的运行时间 ,会产生冲突。
    如:spawn完成任务后,退出进程,从而关闭生成的远程连接TTY窗口,但这窗口下的命令未完成,就会达不到任务需要的效果。
    可通过 设置 spawn延时来 等待 TTY窗口执行完成命令。有以下三种方法:

    1. 通过 命令 expect eof,表示需要读取到文件结束符或到expect 默认时间。
    2. 通过 命令 interact,在执行完成spawn任务后保持交互状态,把控制权交给控制台。这时候可通过手工操作。
    3. 通过 命令 set timeout 10 设置 环境变量 timeout 来保持 spawn等待时间。
# 假如通过SSH登录远程主机后,拷贝文件,那么就需要expect进程等待拷贝完成。
set timeout 10   #第3种方法
spawn rsync -av $file [email protected]$host:$file
#或是 expect eot
# 或是 interact

构建文件分发系统

  1. 目标是通过spawn远程登录服务器,执行rsync命令将本地文件推送到远程主机上。
  2. 通过本地shell调用expect脚本,传递远程主机和同步文件参数。
    #同步脚本名为ryn.expect .本地shell调用。
    # 1远程主机列表和同步文件列表。
    cat ../ip.list
    192.168.10.2
    192.168.10.5
    cat ../file.list
    1.txt
    2.txt
    #本地shell脚本
    cat ../rsync.sh
    #!/bin/bash
    for ip in `cat ip.list`
    do
    echo $ip
        ./ryn.expect $ip list.txt
    done
    # 本地expect同步脚本
    cat ../ryn.expect
    #!/usr/bin/expect
    set host [lindex $rage 0]
    set filelist [lindex $ragv 1]
    set passwd "123!45"
    spawn rsync -av --files-from=$filelist [email protected]$host:/
    expect{
    "yes/no"{ send "yes\r" }
    "password" { send "$passwd\r" }
    }
    expect eof

083-使用shell和expect一键批量分发SSH密钥脚本

083-使用shell和expect一键批量分发SSH密钥脚本

#!/bin/bash
# this scripts comes from oldboy trainning''s student.
# e_mail:70271111@qq.com
# qqinfo:49000448
# function: remote dis ssh key.
# version:1.1
################################################
# oldboy trainning info.
# QQ 80042789 70271111
# site:http://www.etiantian.org
# blog:http://oldboy.blog.51cto.com
# oldboy trainning QQ group: 208160987 45039636
################################################
. /etc/init.d/functions
file="$1"
remote_dir="$2"
if [[ $# -ne 2 ]];then
echo  "usage:$0 argv2"
echo "must have one argvs"
exit
fi
function KNOWN_HOST_REBUILD()
{
#确保本机存在known_hosts列表
[ ! -e ~/.ssh/known_hosts ] && mkdir -p ~/.ssh/ && touch ~/.ssh/known_hosts
local i=$1
sed -i "/^${i} /d" ~/.ssh/known_hosts
expect -c "
spawn /usr/bin/ssh oldboy@${i} echo ok;
expect \"*yes/no)?\";
send \"yes\r\";
expect eof " >/dev/null 2>&1
return 0
[[ $? -ne 0 ]] && echo "$i know host rebuild fail,maybe the server connect error"
}
function PASS_PASSWD()
{
ip=$1
expect -c "
set timeout -1
spawn ssh-copy-id -i id_dsa oldboy@$ip
expect \"*password:\"
send \"oldboy123\r\"
expect eof" >/dev/null 2>&1
}
function FENFA_id_dsa()
{
for ip in `awk ''/^[^#]/{print $1}'' all_client.txt`
do
KNOWN_HOST_REBUILD $ip
PASS_PASSWD $ip
if [[ $? -eq 0 ]];then
action "$ip send id_dsa is successful" /bin/true
else
action "$ip send id_dsa is failed copied" /bin/false
fi
done
}
function FENFA_config()
{
for ip in `awk ''/^[^#]/{print $1}'' all_client.txt`
do
port=$(grep $ip all_client.txt|awk ''{print $2}'')
scp -P${port} -r -p ${file} oldboy@${ip}:~ >/dev/null 2>&1 && \
ssh -p${port} -t oldboy@$ip sudo rsync ~/`basename ${file}` $remote_dir >/dev/null 2>&1
if [[ $? -eq 0 ]];then
action "$ip send $file is successful!!" /bin/true
else
action "$ip send $file is failed!!" /bin/false
fi
done
}
FENFA_id_dsa
FENFA_config

 

#!/bin/bash
# this scripts comes from oldboy trainning''s student.
. /etc/init.d/functions
file="$1"
#本地传送的文件
remote_dir="$2"
#传送到其它服务器的文件,如果是/tmp目录则不受权限控制
if [[ $# -ne 2 ]];then
echo  "usage:$0 argv2"
echo "must have one argvs"
exit
fi
#传参,如果不是2个参数就退出脚本
function KNOWN_HOST_REBUILD()
{

[ ! -e ~/.ssh/known_hosts ] && mkdir -p ~/.ssh/ && touch ~/.ssh/known_hosts
#判断~/.ssh/known_hosts 是文件 ,并且创建文件known_hosts
local i=$1
#声明变量i的值
sed -i "/^${i} /d" ~/.ssh/known_hosts
#如果known_hosts 中有10.0.x.x  开头的密钥,则删除
expect -c "
#命令分发
spawn /usr/bin/ssh oldboy@${i} echo ok;
#嵌套执行命令并输出OK ,用expect语句
expect \"*yes/no)?\";
send \"yes\r\";
expect eof " >/dev/null 2>&1
#>/dev/null 2>&1  输出到黑洞里面去
return 0
#返回值为0则正常,1则不正常
[[ $? -ne 0 ]] && echo "$i know host rebuild fail,maybe the server connect error"
}
#提示你如果输出不为0,则错误
function PASS_PASSWD()
{
ip=$1
expect -c "
set timeout -1
spawn ssh-copy-id -i id_dsa oldboy@$ip
expect \"*password:\"
send \"oldboy123\r\"
expect eof" >/dev/null 2>&1
}
#分发公钥去服务器
function FENFA_id_dsa()
{
for ip in `awk ''/^[^#]/{print $1}'' all_client.txt`
#选取all_client.txt文件中出了#号开头的第一行
do
KNOWN_HOST_REBUILD $ip
#建立know_hosts 中的密钥文件
PASS_PASSWD $ip
#分发送密钥
if [[ $? -eq 0 ]];then
action "$ip send id_dsa is successful" /bin/true
else
action "$ip send id_dsa is failed copied" /bin/false
fi
done
}
function FENFA_config()
{
for ip in `awk ''/^[^#]/{print $1}'' all_client.txt`
do
port=$(grep $ip all_client.txt|awk ''{print $2}'')
取端口号
scp -P${port} -r -p ${file} oldboy@${ip}:~ >/dev/null 2>&1 && \
#scp 传送文件去oldboy的家目录中
ssh -p${port} -t oldboy@$ip sudo rsync ~/`basename ${file}` $remote_dir >/dev/null 2>&1
#文件过去了,开始移动文件
if [[ $? -eq 0 ]];then
action "$ip send $file is successful!!" /bin/true
else
action "$ip send $file is failed!!" /bin/false
fi
done
}
FENFA_id_dsa
# 分发密钥
FENFA_config
#传送文件

 

bash – 如何将变量从shell脚本传递到expect脚本?

bash – 如何将变量从shell脚本传递到expect脚本?

我的 shell脚本如下:
#!/bin/bash

echo "Select the Gateway Server:"
echo "   1. Gateway 1"
echo "   2. Gateway 2"
echo "   3. Gateway 3"

read gatewayHost

case $gatewayHost in
    1) gateway="abc.com" ;;
    2) gateway="pqr.com" ;;
    3) gateway="xyz.com" ;;
    *) echo "Invalid choice" ;;
esac

/mypath/abc

在上面的脚本中,我从用户输入选择中获取网关&试图传递给我的abc.sh脚本,这个脚本在下面是:

#!/usr/bin/expect

set timeout 3
spawn ssh "james@$gateway"
expect "password:"
send "TSfdsHhtfs\r";
interact

但是我无法将shell脚本中的网关变量传递给期望脚本.谁能告诉我如何实现这一目标?请注意,由于遗留原因,我只需要使用shell脚本(不能使用tcl脚本或者不能在期望脚本本身中执行所有操作)

从你的shell脚本:
/mypath/abc $gateway

从您的期望脚本:

#!/usr/bin/expect

set gateway [lindex $argv 0]; # Grab the first command line parameter

set timeout 3
spawn ssh "james@$gateway"
expect "password:"
send "TSfdsHhtfs\r";
interact

expect 实现类似 xshell 的脚本登录

expect 实现类似 xshell 的脚本登录

xshell 免费版本只支持 4 个窗口,且用 xshell 打开的终端在某些情况下会失去快捷键支持(例如 command+backspace)。决定在 Linux 上寻找替代方法,偶然在 v2ex 上看到 expect 命令,它的语法和 shell 有些类似。

#!/usr/bin/expect

spawn ssh vince@jump.test.net -p 1024

expect "Password" {send "******\r"}

以上面这段代码为例,当终端出现 “Password” 时,输入密码。对于简单的 ssh 登录大致如此。

显然,如果 ssh 使用了 2FA,以上方法是行不通的。首先我们需要在 Linux 上生成 Auth code。对于 arch,使用 oathtool。

oathtool --totp -b ****************

重头戏是如何在 expect 脚本中将这个命令的输出转为字符串,这花了我大概几个小时的时间。好在功夫不负有心人。

set code [exec oathtool --totp -b ****************]

不多说了,回家了!

我们今天的关于shell expect SSH 用法一例shell expr的分享就到这里,谢谢您的阅读,如果想了解更多关于0 SHELL训练营--day10_expect、083-使用shell和expect一键批量分发SSH密钥脚本、bash – 如何将变量从shell脚本传递到expect脚本?、expect 实现类似 xshell 的脚本登录的相关信息,可以在本站进行搜索。

本文标签: