目录
在 Linux Shell 编程中,自动化运维是核心目标之一。而实现自动化的关键,往往在于免交互—— 让脚本无需人工干预就能完成原本需要手动输入的操作。本文将基于 Shell 编程中免交互的核心知识,从基础概念到具体工具(Here Document 和 expect),带你一步步掌握免交互技巧,适合初学者快速入门。
一、什么是交互?为什么需要免交互?
1️⃣交互的定义
在计算机领域,交互指的是人与计算机通过对话语言(如图形界面、命令行等)进行信息交换的过程。常见的交互方式有图形用户界面(GUI)、命令行界面(CLI)、语音交互等,目的是提高人与计算机的沟通效率。
2️⃣Linux 中的交互与免交互
在 Linux 中,很多操作需要交互:比如passwd
设置密码时需要输入两次密码,read
命令需要等待用户输入,ssh
登录需要输入密码等。
但在自动化运维中,我们希望脚本能 “自己跑”,不需要人工输入 —— 这就是免交互。免交互能减少重复操作,提高效率,是 Shell 脚本自动化的核心能力。
常见的需要免交互处理的命令:read
、ftp
、passwd
、su
、sudo
、fdisk
、cat
等。
二、Here Document:简单免交互的利器
Here Document(简称 “heredoc”)是 Shell 中一种特殊的代码块,通过 I/O 重定向为交互式命令提供输入,无需临时文件,直接 “就地” 生成输入内容。
1️⃣基本语法
bash
命令 << 标记
内容(标记之间的部分,作为命令的输入)
标记
- 核心作用:将 “标记之间的内容” 作为标准输入,传递给前面的 “命令”。
- 标记规则:
- 标记可以是任意合法字符(常用
EOF
,即 “End Of File”); - 结尾的标记必须顶格写,前面不能有任何字符(包括空格);
- 结尾的标记后面也不能有任何字符(包括空格);
- 开头的标记前后的空格会被自动忽略。
- 标记可以是任意合法字符(常用
2️⃣实用实例
<1>实例 1:用wc -l
统计行数
wc -l
用于统计行数,结合 heredoc 可直接统计标记内的内容行数:
bash
wc -l << EOF
Line 1
Line 2
Line 3
EOF
# 输出:3(表示有3行内容)
<2>实例 2:read
命令免交互
read
命令默认需要等待用户输入,用 heredoc 可提前指定输入内容:
bash
#!/bin/bash
read i << EOF
Hi # 这里的“Hi”会被作为read的输入,赋值给变量i
EOF
echo $i # 输出:Hi
<3>实例 3:passwd
设置密码免交互
passwd
命令设置密码时需要输入两次密码,用 heredoc 可自动完成:
bash
#!/bin/bash
passwd jerry << EOF
This_is_password # 第一次输入密码
This_is_password # 第二次确认密码(必须与第一次一致)
EOF
<4>实例 4:cat
命令写入文件(含变量替换)
用 heredoc 结合cat
可向文件写入内容,支持变量替换:
bash
#!/bin/bash
doc_file="2019.txt" # 定义文件名变量
i="company" # 定义内容变量
cat > $doc_file << HERE
Take him from home to $i # 变量$i会被替换为“company”
HERE
# 执行后,2019.txt内容为:Take him from home to company
<5>实例 5:将内容赋值给变量
heredoc 的内容还能直接赋值给变量,再通过echo
输出:
bash
#!/bin/bash
ivar="Great!"
myvar=$(cat << EOF
This is Line 1. $ivar # 变量$ivar会被替换为“Great!”
EOF
)
echo $myvar # 输出:This is Line 1. Great!
3️⃣格式控制
heredoc 支持两种特殊格式控制,满足更多场景需求:
<1>关闭变量替换
默认情况下,heredoc 会自动替换变量值。如果希望按字符原样输出(不替换变量),给标记加单引号即可:
bash
#!/bin/bash
kgc=100
cat << 'EOF' # 标记加单引号,关闭变量替换
This is Line 1. $kgc # $kgc会原样输出,不会变为100
EOF
# 输出:This is Line 1. $kgc
<2>去掉每行前的 TAB 字符
如果内容中每行开头有 TAB 字符(用于缩进),可在标记前加-
,自动去除 TAB:
bash
#!/bin/bash
cat <<- 'EOF' # 标记前加“-”,去除内容中的TAB
Line 1(前面有TAB)
Line 2(前面有TAB)
EOF
# 输出:
# Line 1(前面有TAB)
# Line 2(前面有TAB)(TAB被自动去除)
4️⃣多行注释
Shell 默认用#
做单行注释,heredoc 可实现多行注释:
bash
#!/bin/bash
kgc=100
: << DO-NOTHING # “:”是空命令,后面的内容会被忽略(即注释)
这是第一行注释
这是第二行注释
bash不会执行这里的内容
DO-NOTHING
echo $kgc # 输出:100(注释不影响其他代码)
三、expect:复杂交互的解决方案
Here Document 适合简单交互场景,对于更复杂的交互(如ssh
登录、远程操作),需要用expect
工具。expect
基于 tcl 语言,专门用于自动化控制交互过程。
1️⃣安装 expect
bash
sudo apt install expect # Ubuntu/Debian
# 或
sudo yum install expect # CentOS/RHEL
2️⃣核心参数与语法
expect 脚本的核心是 “匹配输出→发送输入”,关键参数如下:
参数 / 命令 | 作用 |
---|---|
#!/usr/bin/expect |
脚本解释器,表明这是 expect 脚本 |
spawn |
启动一个进程(如ssh 、passwd ),并跟踪其交互信息 |
expect "字符串" |
等待进程输出包含 “字符串” 的内容 |
send "内容\r" |
向进程发送 “内容”,\r 表示回车(必须加) |
expect eof |
等待进程执行结束(脚本结束) |
interact |
执行完后保持交互状态(手动操作) |
set timeout N |
设置超时时间(N 秒,-1 表示永不超时) |
exp_continue |
继续匹配后续内容(不退出当前 expect 块) |
send_user "信息" |
输出信息到终端(类似echo ) |
[lindex $argv n] |
接收外部参数(n 从 0 开始,0 是第一个参数) |
3️⃣实用实例
<1>实例 1:单一分支交互(设置用户密码)
bash
#!/bin/bash
user="mtt"
password="nt"
useradd $user # 先创建用户
# 用expect处理passwd的交互
expect << EOF
spawn passwd $user # 启动passwd进程,跟踪交互
expect "New password:" # 等待输出“New password:”
send "$password\r" # 发送密码
expect "Retype new password:" # 等待输出“Retype new password:”
send "$password\r" # 发送确认密码
expect eof # 等待进程结束
EOF
<2>实例 2:多分支交互(ssh
自动登录)
ssh
登录可能遇到多种场景(首次登录需确认、输入密码、连接失败等),用多分支处理:
bash
#!/usr/bin/expect
set timeout 30 # 超时时间30秒
set hostname [lindex $argv 0] # 接收第一个参数(目标主机)
set password [lindex $argv 1] # 接收第二个参数(密码)
spawn ssh $hostname # 启动ssh进程
expect {
"Connection refused" { exit } # 连接被拒绝,退出
"Name or service not known" { exit } # 主机不存在,退出
"Are you sure you want to continue connecting (yes/no)?" { # 首次登录确认
send "yes\r"
exp_continue # 继续匹配后续内容
}
"password:" { send "$password\r" } # 输入密码
}
interact # 登录后保持交互(可手动操作)
执行脚本:
bash
./expect_auto_ssh.sh 192.168.141.130 abc123 # 主机IP+密码作为参数
四、总结
免交互是 Shell 自动化运维的核心技能,掌握这两种工具能大幅提升脚本效率:
- Here Document:适合简单交互(
read
、passwd
、文件写入),语法简洁,无需额外安装。 - expect:适合复杂交互(
ssh
、远程操作),功能强大,需要提前安装。