Here Document
它在 Linux Shell 中使用 I/O 重定向的方式将命令列表提供给交互式程序或命令
Here Document 是标准输入的一种替代品
帮助脚本开发不必使用临时文件来构建输入信息,而是直接生成文件并用作命令的标准输入
示例
[root@bogon ~]# cat > my.cof << xiaojing
> asdfaf
> asdfs
> asdcvd
> asdv
> xiaojing
[root@bogon ~]#
标记可以使用任意的合法字符
结尾的标记一定要顶格写,前面不能有任何字符
结尾的标记后面也不能有任何字符(包括空格)
开头的标记前后的空格会被省略掉
什么是免交互
它通过I/O重定向的方式将命令列表提供给交互式程序或命令,从而避免了用户的手工输入,提高了脚本的自动化程度
统计文件内有多少行内容
wc -l 命令后面直接跟文件名就可以
Here Document 格式控制
关闭变量替换的功能
passwd lisi << 'eof'
#单引号的作用代表以下特殊字符,失去特殊含义
123
123
eof
去掉每行之前的 TAB 字符(抑制各行首 TAB 的作用)
[root@localhost ~]# vim here_format_tab.sh
#!/bin/bash cat <<-'EOF'
This is Line 1.
$kgc
EOF
[root@localhost ~]# sh here_format_tab.sh
This is Line 1.
$kgc //输出结果同上一示例
变量设定
标记之间有变量被使用,会先替换变量值
[root@localhost ~]# vim here_var_replace.sh
#!/bin/bash doc_file="2019.txt" i="company"
cat > $doc_file << HERE Take him from home to $i HERE
[root@localhost ~]# chmod +x here_var_replace.sh [root@localhost ~]# ./here_var_replace.sh [root@localhost ~]# cat 2019.txt
Take him from home to company
expect 概述
expect
可以让一些需要交互的任务自动化地完成
进行自动化控制和测试的工具
主要解决 shell 脚本中不可交互的问题
expect 安装
1.安装软件
yum -y install expect
2.编辑ssh连接脚本文件
#!/usr/bin/expect
#设置超时时间
set timeout 60
#连接地址
spawn ssh root@192.168.27.131
expect {
"*(yes/no)*" { send "yes\r"; exp_continue } # 如果出现"yes/no"提示,发送"yes"并继续等待
"*password:*" { send "123456\r" } # 使用更具体的匹配模式
}
#确认登录成功,能匹配到#号就代表成功
expect "*#" {send "ifconfig ens33 \r" }
#退出方式
interact
# expect eof :等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
# interact : 执行完成后保持交互状态, 把控制权交给控制台,这时可以手动输入信息。 需要注意的是,expect eof 与 interact 只能二选一。
脚本
#!/usr/bin/expect
# expect 将超时时间设置为 60 秒
set timeout 60
# 记录日志文件
log_file test.log
# 开启控制台输出,为0时,控制台不输出
log_user 1
# $argc 表示参数个数
if {$argc<1} {
# send_user相当于shell的echo
send_user "usage: $argv0 <param1><param2> ... "
exit
}
set hostname [lindex $argv 0]
set password [lindex $argv 1]
# spawn 后面通常跟一个命令,表示开启一个会话、启动进程,并跟踪后续交互信息
spawn ssh root@${hostname}
expect {
"(yes/no)"
# 匹配的(yes/no)时自动输入yes,exp_continue 表示允许 expect 继续向下执行指令
{send "yes\r"; exp_continue}
"*password"
{send "$password\r"}
}
expect "*#" {send "ifconfig\r"}
# expect eof :等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
# interact : 执行完成后保持交互状态, 把控制权交给控制台,这时可以手动输入信息。 需要注意的是,expect eof 与 interact 只能二选一。
interact
创建用户脚本
#!/bin/bash
user=$1
password=$2
useradd $user
expect << EOF
# 开启一个进程跟踪 passwd 命令,expect 只能捕捉该进程信息
spawn passwd $user
# 匹配输出信息"New password:"
expect "New password:"
# 自动输入密码 ,英文版的可以捕捉,中文版的可能会报错
send "${password}\r"
# 匹配输出信息"Retype new password:"
expect "Retype new password:"
# 自动输入密码
send "${password}\r"
# 等待结束标记
expect eof;
EOF
课后作业 免交互式等ssh
#!/bin/bash
# 检查是否安装expect命令
check_expect_cmd() {
#查找命令是否存在,返回0存在,否则是不存在
if command -v expect &> /dev/null ;then
return 0
else
return 1
fi
}
#安装expect命令
install_expect() {
#判断操作系统,根据系统不同,执行不同的安装指令
if command -v dnf &> /dev/null ;then
dnf -y install expect
elif command -v yum &> /dev/null ;then
yum -y install expect
elif command -v apt-get &> /dev/null ;then
apt-get -y install expect
else
echo "$(data) ERROR:未知错误,请手动添加"
fi
}
#执行命令
runcmd() {
local hostip=$1
local user=$2
local password=$3
local port=$4
local cmd=$5
expect << EOF
#定义超时时间
set timeout 60
#追踪ssh命令
spawn ssh -p ${port} ${user}@${hostip}
expect {
"(yes/no)"
{ send "yes\r";exp_continue}
"*password"
{ send "${password}\r"}
}
#匹配密码错误时退出
expect "*please try again*" {
send_user "\nERROR: password error\n"
}
#执行命令
expect -re "(#|\$)" { send "${cmd}\n"}
expect -re "(#|\$)" { send "exit\n"}
#等待结束
expect eof;
EOF
}
if ! check_expect_cmd ;then
install_expect
fi
runcmd "192.168.27.129" "root" "123456" "22" "pwd"
etc/os-release Linux中都存在这个文件,可以用来过滤操作系统
dnf是yum命令的升级版:
[root@bogon ~]# cat host.cfg
[test]
192.168.27.131 username=root password=123456 port=22
192.168.27.110 username=root password=123456 port=22
[kgc]
192.168.27.128 username=root password=123456 port=22
192.168.27.131 username=root password=123456 port=22
根据文本文件连接
#!/bin/bash
file_name="hosts.cfg"
# 判断配置文件是否存在
check_file() {
local file=$1
if [ ! -f "$file" ];then
echo "$(date) ERROR: ${file} 不存在"
exit 1
fi
}
# 判断组是否存在
check_group() {
local group=$1
grep -w "\[${group}\]" $file_name &> /dev/null
if [ "$?" -eq 0 ];then
return 0
else
exit 1
fi
}
# 检测是否有expect命令
# 返回0表示存在命令,返回1表示不存在命令
check_expect_cmd() {
if command -v expect &> /dev/null ;then
return 0
else
return 1
fi
}
# 安装expect
install_expect() {
if command -v dnf &> /dev/null ;then
dnf -y install expect
elif command -v yum &> /dev/null ;then
yum -y install expect
elif command -v apt-get &> /dev/null ;then
apt-get -y install expect
else
echo "$(date) ERROR: 未知的操作系统,请手动安装expect命令"
fi
}
# 执行命令
runcmd() {
local hostip=$1
local user=$2
local password=$3
local port=$4
local cmd=$5
expect << EOF
# 定义超时时间
set timeout 10
# 追踪ssh命令
spawn ssh -p ${port} ${user}@${hostip}
expect {
"(yes/no)"
{ send "yes\r";exp_continue }
"*password"
{ send "${password}\r" }
}
# 匹配到密码错误时退出
expect "*please try again*" {
send_user "\nERROR: password error\n"
}
# 执行命令
expect -re "(#|\$)" { send "${cmd}\n" }
expect -re "(#|\$)" { send "exit\n" }
# 等待结束标记
expect eof;
EOF
}
# 获取指定组里面的信息
get_group_info() {
local group_name=$1
local ip
local user
local password
local port
local cmd=$2
local info=$(awk -v group="$group_name" '
$0 ~ "^\\[" group "\\]$" { test=1; next }
$0 ~ "^\\[" { test=0 }
test && /^[^[:space:]]+/{ print $1, $2, $3, $4 }
' "$file_name")
echo "$info" | while IFS= read -r line;do
# 获取相关信息
ip=$(echo "${line}" | awk '{print $1}')
user=$(echo "${line}" | awk '{print $2}' | awk -F '=' '{print $2}')
password=$(echo "${line}" | awk '{print $3}' | awk -F '=' '{print $2}')
port=$(echo "${line}" | awk '{print $4}' | awk -F '=' '{print $2}')
# 执行命令
runcmd "${ip}" "${user}" "${password}" "${port}" "${cmd}"
done
}
main() {
while getopts "f:g:c:h" opt; do
case $opt in
f)
file_name=$OPTARG
;;
g)
group=$OPTARG
;;
c)
cmd=$OPTARG
if [ -z "$cmd" ]; then
echo "no command"
exit 1
fi
;;
h)
echo "Usage: $0 -f hosts.cfg -g group -c cmd"
esac
done
# 判断是否有命令
if ! check_expect_cmd ;then
install_expect
fi
# 检测配置文件是否存在
check_file "$file_name"
# 检测组是否存在
if [ "$?" -eq 0 ] ;then
check_group "$group"
else
exit 1
fi
# 批量执行命令
get_group_info "$group" "$cmd"
}
if [ "$#" -eq 0 ];then
main -h
exit 1
fi
main "$@"