在 Shell 脚本中进行交互的一些心得
我们在写 shell 脚本时经常会遇到一些需要交互的操作,比如修改某个文件,或是使用 yum install
ssh-keygen
certbot --nginx
等操作时,需要输入一些指令如 “y”, “Enter” 和其他的一些信息。
我们写脚本就是为了自动操作,怎么可以等命令执行一会之后在按个回车进行下一步呢?既然我知道接下来要输入什么命令,我告诉你你帮我输入了不就得了?
聪明的我们想到了一些办法来避免这种无谓的等待,记录下来分享给大家
1. 自动化输入
1.1 输入单个指令
这里用 yum install
来进行演示 (假设不使用 -y
参数)
1 | echo "y" | yum install wget |
如果要求输入回车,可以使用 echo 指令的参数 -e
+ \n
进行操作
1 | echo -e "\n" | yum remove wget |
**`echo -e` 的小知识**
若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:\a
发出警告声;\b
删除前一个字符;\c
最后不加上换行符号;\f
换行但光标仍旧停留在原来的位置;\v
与\f 相同;\n
换行且光标移至行首;\r
光标移至行首,但不换行;\t
插入 tab
符号;\\
插入 ‘' 字符;\nnn
插入 nnn(八进制)所代表的 ASCII 字符;
1.2 输入多行指令
输入多行指令我们需要借助输入重定向操作符 <<
以下面这个脚本为例
1 |
|
借助 <<
符号进行自动化输入
1 |
|
但是有时候这种方法并不生效,比如 ssh-keygen
命令,那只有借助强大的 expect
命令了
1.3 借助 expect
进行交互
在使用 expect
前需要进行安装,方法很简单,以 CentOS 为例,只需要运行 yum install -y expect
即可
expect 有两种用法,一种是直接写 expect 解释器的脚本,和 bash 类似,以 #!/usr/bin/expect
开头
下面是一个合格的 expect 脚本示例
1 |
|
需要注意的是,在 expect 解释器内, 除了几个特定关键字的命令,其他命令都不可用,这种方式适用于执行命令较少,单次需要交互较多的自动化脚本
第二种用法是在 bash 脚本中执行 expect 配合重定向操作符, 在有大量脚本需要执行的情况下推荐使用该方式
下面是我在 certbot
命令时使用的 shell 脚本,以供参考
1 |
|
2. 修改文件
2.1 在文件中增加内容
我们想要将某个命令的输出写入到文件中进行保存,比如日志、新增一行配置,可以借助输出重定向符号 >
>>
来实现
1 | who > log.txt # > 符号将会先清空 log.txt 然后以 who 的输出写入到文件中 |
那如果需要写入多行该怎么办呢?虽然也可以借助 echo -e
+ \n
来实现,但是我们还有其他更优雅的办法
借助 cat
命令配合 <<
符号也可以达到我们的目的
1 | cat > log.txt << EOF |
WHY?
cat
命令如果不接受任何参数,将会进入交互式界面,输入什么就会输出什么;
配合>
符号将cat
的输出写入到文件log.txt
中;
而<<
我们前面介绍过,会将多行输入重定向到前面的命令cat
中
2.2 修改文件的内容
关于修改文件的内容,如何在不借助 vim 等工具情况下进行呢?
有请我们强大的 sed
命令登场!!
sed [选项] 指令 文件
其中选项有
-n
忽略没有修改的内容-i
原地修改文件而不输出-r
拓展正则表达式
指令为一个字符串,由 2 个部分组成 条件
命令
,条件用于约束,指令进行操作
一个正常的替换命令长这样
1 | sed -i "/^user/ s/nginx/mutoe/" /paht/to/nginx.conf |
其中/^user/
为条件,查找以 “user” 开头的一行;s/nginx/mutoe/
为命令,s
是替换,这条命令意思是将 nginx
替换为 mutoe
sed 支持的命令有很多,约有 15 中,列举一些常见的命令
i
插入a
追加d
删除行c
替换行s
替换指定内容
关于
sed
的更多用法,可以参考我的 《Linux 学习笔记》 “sed 非交互式编辑” 部分
以下面的 nginx 配置片段为例
1 | user nginx; |
首先我们将 nginx 的启动用户改为自定义用户
1 | sed -i "1c user mutoe;" /path/to/nginx.conf |
-i
意思是将输出 “in-placed” 直接替换文件内容而不是作为输出
“1c user mutoe;” 是指将第 1 行替换(c)为”user mutoe;”
接下来我们去除 #gzip on;
前的空格,难度在于我们并不知道改行配置位于哪一行,没关系,我们借助正则表达式先找到这一行
1 | sed -i "/#gzip\s+on;/s/#//" /path/to/nginx.conf |
最后我们删除文件的最后一行
1 | sed -i "$d" /path/to/nginx.conf |
好了,所有内容到这里就结束啦,如果看的不过瘾,这里有我在实际使用中的一些脚本,以供参考。
如果你有任何疑问或是支持,欢迎在下方留言。