1.安装expect

expect用于shell脚本中自动交互,其是基于tcl编程语言的工具。所以安装expect首先安装tcl。本文中使用的是​​expect5.45​​​和​​tcl8.6.6​​。

安装tcl

[root@tseg0 /]$ mkdir /tools
[root@tseg0 /]$ tar -zxvf tcl8.6.6-src.tar.gz
[root@tseg0 /]$ cd tcl8.6.6/unix/
[root@tseg0 /]$ ./configure
[root@tseg0 /]$ make
[root@tseg0 /]$ make install

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

安装expect

[root@tseg0 /]$ cd /tools
[root@tseg0 /]$ tar -zxvf expect5.45.tar.gz
[root@tseg0 /]$ cd expect5.45/
[root@tseg0 /]$ ./configure --with-tcl=/usr/local/lib/ --with-tcl include=/tools/tcl8.6.6/generic/
[root@tseg0 /]$ make
[root@tseg0 /]$ make install

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

shell脚本实现scp传输

命令解释

-c 表示可以在命令行下执行except脚本; 

spawn 命令激活一个unix程序来交互,就是在之后要执行的命令; 

expect “aaa” 表示程序在等待这个aaa的字符串; 

send 向程序发送字符串,expect和send经常是成对出现的,比如当expect“aaa”的时候,send“bbb”。

执行脚本

#! /bin/sh
expect -c "
spawn scp -r /home/tseg/hello $name@10.103.240.33:/home/$name/
expect {
\"*assword\" {set timeout 300; send \"$pass\r\"; exp_continue;}
\"yes/no\" {send \"yes\r\";}
}
expect eof"

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

解释: 

第二行: -c 表示可以不用与控制台交互; 

第三行:spawn激活一个scp的unix程序; 

第五行:expect期待含有“assword”的字符串,设置连接时间最大为300毫秒,如果出现这个字符串,就send 变量pass代表的密码字符串, exp_continue表示执行下面的匹配; 

第六航:expect期待含有“assword”的字符串,设置连接时间最大为300毫秒,如果出现这个字符串,就send 变量pass代表的密码字符串; 

第八行:表示结束。



####sample 1:

1.vi 1.sh

#! /bin/sh

export pass=123456
export name=root

expect -c "
spawn scp -r /home/tseg/hello $name@10.103.240.33:/home/$name/
expect {
\"*assword\" {set timeout -1; send \"$pass\r\"; exp_continue;}
\"yes/no\" {send \"yes\r\";}
}
expect eof"
set timeout -1   ------->>>>>>注意此处的-1,-1表示永不超时,也就是:等 scp 命令正常执行完成之后,控制权会转移到下一行。

set timeout 300 ------->>>>>>300表示300秒后超时,在超时之后,控制权会移到下一行;若在超时时间之内,程序运行完,则控制权也会转移到下一行。

2. nohup sh 1.sh


####sampe 2


shell 脚本sftp 文件下载


#!/bin/bash
sftp_Host="192.168.1.1"
sftp_userName="admin"
sftp_passWord="admin"
sftp_port=22
sftpRemotePath="/data/fiels"
sftpLocalPath="/root/sftp"
current=$(date "+%Y-%m-%d %H:%M:%S")

echo "当前时间是:$current"

if [[ $# == 0 ]]; then
yesterday=$(date "+%Y%m%d" -d "-1 days")
fi
if [[ $# == 1 ]]; then
yesterday=$1
fi
myDir=$sftpLocalPath
if [[ ! -d $myDir ]]; then
mkdir -p $myDir
fi
sftpLoadPath=$sftpRemotePath$yesterday
fileFilter=$yesterday*.gz

# SFTP非交互式操作
sftp_download()
{
expect <<- EOF
set timeout 5
spawn sftp -P $sftp_port $sftp_userName@$sftp_Host

expect {
"(yes/no)?" {send "yes\r"; expect_continue }
"*assword:" {send "$sftp_passWord\r"}
}
expect "sftp>"
send "cd $sftpLoadPath \r"
expect "sftp>"
send "lcd $myDir \r"
expect "sftp>"
set timeout -1
send "mget $fileFilter \r"
expect "sftp>"
send "bye\r"
EOF
}

unGzipFiles(){
cd $myDir
fileList=`ls *`
fileArr=($fileList)
for fileName in ${fileArr[@]}
do
echo "开始解压文件:$fileName"
gzip -d $fileName
done

}

reNameFiles(){
cd $myDir
fileList=`ls *`
fileArr=($fileList)

for fileName in ${fileArr[@]}
do
echo "reNameFile :$fileName"
mv $fileName $fileName".csv"
done
}

echo "执行sftp下载操作 : 数据日期:$yesterday"
sftp_download
echo "$yesterday 文件下载完成"
echo "执行解压操作"
unGzipFiles
echo "重命名文件"
reNameFiles



linux expect中的timeout设定

在做日志分析工具时,发现在屏幕上拿到日志结果会有点慢,然后查了一下expect ssh timeout的设置,原来是这里有个默认时间的问题,所以整理一下:

expect脚本我们都知道,首先spawn我们要执行的命令,然后就给出一堆expect的屏幕输出,如果输出match了我们的expect的东西,我们就会send一个命令上去,模拟用户输入。

但是expect中等待命令的输出信息是有一个timeout的设定的,默认是10秒。这个特性是防止那些执行死机的命令的。一旦到了这个timeout,还是没有屏幕输出的话,expect脚本中下面的代码就会执行。或者我们在expect脚本中如果定义了timeout的响应代码的话,这些代码就会被执行。

解决这样的问题非常简单,最简单的办法就是在expect脚本的开头定义:

set timeout -1 -- 没有timeout set timeout XX -- 设定具体的timeout时间(秒)



###sample

感谢吴老师

expect交互式安装软件

公司一些宿主机需要安装软件,吴老师要求写一个安装脚本;

脚本思路:首先要把安装的包拷贝到每台机器上,然后要让每台机器都运行一次安装命令;就想到了应用scp、ssh命令,但这两个命令需要输入对端密码,需要与机器交互;此时可以应用交互式命令expect。

expect可以实现自动交互:

set:设置变量;set timeout -1,永不超时;set timeout 300,300秒后没有expect内容出现退出;

spawn:想要执行的命令,你想要进行的交互命令;

expect:等待命令提示信息,交互的过程,系统会给一些输入密码等提示,expect就是抓取其中关键字,当expect抓取到了后面的关键字,就会执行send。

send:发送信息,完成交互,检测到关键字后向交互界面输入的信息。

interact:

expect eof:结束退出;

代码如下:

#!/bin/bash

#

SERVERS="192.168.254.11 192.168.254.12 192.168.254.13"  //需要安装的所有主机

PASSWORD="123456"  //统一密码

VIB_FILE="/app/vmware-esx-MegaCli-8.07.07.vib"  //安装包路径

SHELL_FILE="/app/megacli_install.sh"  //安装脚本(脚本中就一条安装vib文件的命令)


vib_shell_copy(){

expect << EOF

set timeout -1  //设置超时时间

spawn scp -o StrictHostKeyChecking=no $VIB_FILE $SHELL_FILE $1:/tmp/  //spawn调用scp命令将安装包和安装脚本copy到$1主机的tmp目录下

expect "assword:"   //检测关键信息

send "$2\r"  //输出信息$2(密码),通过scp密码交互

expect eof  //完成expect

EOF

}


vib_install(){

expect << EOF

set timeout -1

spawn ssh -o stricthostkeychecking=no root@$1 "sh /tmp/megacli_install.sh"

expect "assword:"

send "$2\r"

expect eof

EOF

}


for SER in $SERVERS

do vib_shell_copy $SER $PASSWORD &> /dev/null

echo "$SER copy successed"

vib_install $SER $PASSWORD &> /dev/null

echo "$SER install successed"

done

测试了一下脚本没问题,在生产运行脚本,第四五台机器时脚本就走不动了,咨询一下吴老师,是scp、ssh命令会有首次交互确认的问题,选项 -o stricthostkeychecking=no 关闭主机密钥检查就OK了。

标签: Linux shell




某产品的插件基本都是一步步安装,需要输入一些相对比较专业的参数,对于没有接触过该产品的人而言,就不知道怎么选择。而某客户对于该插件的需求是恒定的,则可以通过expect来自动执行安装,降低了对售后人员的技术要求。

解决方法

!/usr/bin/expect

spawn bash install.bin

set openstack 11

expect "*1*12*select:" { send "$openstack\r" }

set install 1

expect "*operation:" { send "$install\r" }

set expert n

expect "*expert*:" { send "$expert\n" }

set sdnip 2009:d::101

expect "*sdn*" { send "$sdnip\n" }

set https y

expect "*HTTPS*:" { send "$https\n" }

set ssl n

expect "*validation*" { send "$ssl\n" }

set port 8443

expect "*8443*" { send "$port\n" }

set username root

expect "*name:" { send "$username\n" }

set passwd password

expect "*password:" { send "$passwd\n" }

interact


###sample

##remove -P 22 because we meet error :exec: 22: No such file or directory

###add -o stricthostkeychecking=no to 首次登陆时候 提示 avoid Are you sure you want to continue connecting ###(yes/no)?

##remove -P 22 from sftp because we meet error :exec: 22: No such file or directory,Couldn't read packet: ##Connection reset by peer

##in windows nbu master : check security management _ token management : token is MVFNJBPGRJXHCMFU

###check another day token still is MVFNJBPGRJXHCMFU


expect <<- EOF

set timeout 5

spawn sftp -o stricthostkeychecking=no useradmin@10.200.1.1

expect {

"(yes/no)?" {send "yes\r"; expect_continue }

"*assword:" {send "user@pass\r"}

}

expect "sftp>"

send "cd /dbsoft/nbusoft/NBU8.1 \r"

expect "sftp>"

send "lcd /tmp/nbu \r"

expect "sftp>"

set timeout -1

send "mget rman.sh \r"

expect "sftp>"

send "mget NetBackup_8.1.2_CLIENTS2.tar.gz \r"

expect "sftp>"

send "mget rman_arc.sh\r"

expect "sftp>"

send "mget mysql_backup.sh\r"

expect "sftp>"

send "mget mysqlbackup_5.7\r"

expect "sftp>"

send "bye\r"

EOF



因为expect 使用 sftp 可以会存在泄露密码,安全隐患


登录

ssh免密登录远程执行命令/脚本 原创

2018-06-27

5点赞

p7+

码龄5年

关注

执行一条命令

ssh 192.168.1.12 source /etc/profile

1

执行多条命令(如果有空格,那么需要使用双引号)

ssh 192.168.222.102 "source /etc/profile;/root/apps/test.sh"

1

执行脚本的坑

通过ssh执行命令,是没有环境变量的,例如远程启动zookeeper。我们知道,zookeeper是需要java环境的支持,但是我们通过ssh启动其他服务器上的zookeeper时,虽然显示启动成功,

但是切换到zookeeper服务器查看进程时,却发现没有zookeeper的进程。为什么呢?

我们知道,在/etc/profile中配置JAVA_HOME后需要source /etc/profile后,java环境才生效,而linux重启后,

即使不手动执行source /etc/profile,java环境也是有效的,这是因为linux在启动时,已经初始化了/etc/profile文件。

通过ssh远程执行脚本或命令时,如果执行的东西是需要环境支持的,那么我们必须要先初始化环境。例如:test.sh需要java的支持,并且/etc/profile中配置了java的路径

ssh 192.168.222.102 "source /etc/profile;/root/apps/test.sh"

1

免密登陆的zookeeper自启动脚本

#!/bin/bash

SERVERS="pc-server1 pc-server2 pc-server3"

PASSWORD=root

# 自动复制ssh密钥到相应的主机

auto_ssh_copy_id(){

expect -c "set timeout -1;

spawn ssh-copy-id $1;

expect {

*(yes/no)* {send -- yes\r;exp_continue;}

*assword:* {send -- $2\r;exp_continue;}

eof {exit 0;}

}";

}

ssh_copy_id_to_all(){

for SERVER in $SERVERS

do

auto_ssh_copy_id $SERVER $PASSWORD

done

}

ssh_copy_id_to_all

zk(){

for SERVER in $SERVERS

do

ssh root@$SERVER "source /etc/profile;zkServer.sh $1"

done

}

case $1 in

start)

zk $1

;;

stop)

zk $1

;;

status)

zk $1

;;

*)

echo "Usgae:{start|stop|status}"

esac


##sample 因为登录用户不是 root,而是 root 权限的ddadmin ,配置ssh 免密登录,感谢zyp,如果上一次已经配置了一次信任关系,则这一部分再次不用执行,ssh-keygen -P '' ,

##否则,可能导致之前的信任关系失效。                      

su - root

ssh-keygen -P ''          《-如果上一次已经配置了一次信任关系,则这一部分再次不用执行     ,否则,可能导致之前的信任关系失效        

ssh-copy-id -i ddadmin@ip

验证

ssh useradmin@ip


如果碰到报错:/usr/bin/ssh-copy-id: ERROR: No identities found

# ssh-copy-id -i adadmin@host

/usr/bin/ssh-copy-id: ERROR: No identities found

ssh-copy-id -i /root/.ssh/id_rsa.pub adadmin@host

ssh adadmin@host


###sample 目的dep_rman_shell.sh 将文件推送到远程,同时远程执行对应脚本,远程修改主机的rman 脚本

file1: dep_rman_shell.sh

#!/bin/bash

#add more hosts

echo "please make sure config file (rman_shell_config.sh) is ok"

head -n 6 rman_shell_config.sh

echo "please input servers:(10.10.10.10 10.20.20.20.20)"

read SERVERS

echo "SERVERS=$SERVERS"

echo "please input os password:"

read PASSWORD

echo "password=$PASSWORD"

#VIB_FILE="/tmp/nbu/host.tmp"

SHELL_FILE="/dbsoft/nbusoft/NBU8.1/config/shell/rman_shell_config.sh"

#--remove set timeout -1 because it running quickly,have already config have hosts' trust info

vib_shell_copy(){

expect << EOF

set timeout -1

spawn scp -o StrictHostKeyChecking=no $SHELL_FILE useradmin@$1:/tmp/

expect "assword:"

send "$2\r"

expect eof

EOF

}

#--remove set timeout -1 because it running quickly ,have already config have hosts' trust info

vib_install(){

expect << EOF

set timeout -1

spawn ssh -o stricthostkeychecking=no useradmin@$1 "sh /tmp/rman_shell_config.sh"

expect "assword:"

send "$2\r"

expect eof

EOF

}

#--add more password in list ,have already config have trust info

for SER in $SERVERS

#do vib_shell_copy $SER $PASSWORD &> /dev/null

#for PASSWORD in $PASS

do vib_shell_copy $SER $PASSWORD

echo "$SER copy successed"

#vib_install $SER $PASSWORD &> /dev/null

vib_install $SER $PASSWORD

echo "$SER install successed"

done


-file 2 rman_shell_config

export sid=ntbs

export user=opntbs

export arch_policy=rman_ntbs_arc

export host=pntbsdb_svc

export ora_policy=rman_ntbsdb

hostname

RSTAT=`ps -ef|grep $user|grep pmon |wc -l`

if [ "$RSTAT" = 0 ]

then

su - $user <<!

cd /usr/openv/netbackup/bin

expect <<- EOF

set timeout 20

spawn ./oracle_link

expect "Do you want to continue? (y/n) \[n\] "

send "y \r"

expect "to make sure the linking process was successful"

EOF

!

echo "install is ok"

else

echo "please check"

fi

cd /usr/openv/netbackup/ext/db_ext/shell

mv sample1 $sid


#cd /usr/openv/netbackup/ext/db_ext/shell

#mv sample1 $sid

cd $sid

perl -p -i -e "s/opigfs/$user/g" *.sh

perl -p -i -e "s/pigfsdb01/$host/g" *.sh

perl -p -i -e "s/rman_igfs_arc/$arch_policy/g" *.sh

perl -p -i -e "s/rman_igfs_new/$ora_policy/g" *.sh


--file 3 readme

1.first edit config file

2.then sh dep*.sh ,input two ip and password


-注意;

上面脚本需要输入主机密码,如果信任关系建立好,不需要输入密码, 如下命令即可

scp $VIB_FILE $SHELL_FILE useradmin@$1:/backup/suseript/nbu

ssh useradmin@$1 "sh /backup/suseript/nbu/media_config.sh"


### sample 3 目的 dep_media.sh 将配置文件host.tmp 传到对应的机器上,同时运行media_config.sh 将运行一系列命令


file 1: dep_media

#!/bin/bash

#add more hosts


echo "please make sure config file (host.tmp) is ok"

echo "make sure all host directroy /backup/suseript/nbu is ok"

head -n 6 host.tmp

echo "please input above info yes/no"

read option

echo "option=$option"

SERVERS="dbsanmd01 dbsanmd02 dbsanmd03 dbsanmd04"

VIB_FILE="/backup/suseript/nbu/host.tmp"

SHELL_FILE="/backup/suseript/nbu/media_config.sh"

#--remove set timeout -1 because it running quickly,have already config have hosts' trust info

vib_shell_copy(){

scp $VIB_FILE $SHELL_FILE useradmin@$1:/backup/suseript/nbu

}

#--remove set timeout -1 because it running quickly ,have already config have hosts' trust info

vib_install(){

ssh useradmin@$1 "sh /backup/suseript/nbu/media_config.sh"

}

#--add more password in list ,have already config have trust info

for SER in $SERVERS

#do vib_shell_copy $SER $PASSWORD &> /dev/null

#for PASSWORD in $PASS

#do vib_shell_copy $SER $PASSWORD

do vib_shell_copy $SER

echo "$SER copy successed"

#vib_install $SER $PASSWORD &> /dev/null

#vib_install $SER $PASSWORD

vib_install $SER

echo "$SER install successed"

done

##for local

sh /backup/suseript/nbu/media_config.sh


bpnbat -login -info /backup/script/nbu/nbu.info

os_name_list=`cat /backup/script/nbu/host.tmp|grep -v "#" |awk ' { print $2 }'|grep -v svc`

for os_name in ${os_name_list}

do

os_name_svc=`cat /backup/script/nbu/host.tmp|grep -v "#" |awk ' { print $2 }'|grep svc`

if [ ! -n "$os_name_svc" ]

then

echo "nothing to do"

else

echo $os_name

nbhostmgmt -add -host $os_name -mappingname $os_name_svc

nbhostmgmt -add -host $os_name -mappingname $os_name_svc -isshared

fi

done

echo "####please ingore the error Exit Status 8715/8724#######"



file2: media_config

hostname

cp /etc/hosts /etc/hosts.bak

/usr/openv/netbackup/bin/bpclntcmd -clear_host_cache

cat /backup/script/nbu/host.tmp >> /etc/hosts

os_name_list=`cat /backup/script/nbu/host.tmp|grep -v "#" |awk ' { print $2 }'`

for os_name in ${os_name_list}

do

echo $os_name

/usr/openv/netbackup/bin/admincmd/bptestbpcd -client $os_name -verbose

done

ls


file 3: host.tmp

##202007###

5.6.1.20

db


file 4:

cat /backup/script/nbu/nbu.info

unixpwd

swnubmaster01

cradmin

CR@zh123