当前位置:首页 > 尘凡 > 正文内容

在 Shell 脚本中进行交互的一些心得

满纸空言3年前 (2021-04-21)尘凡13930

我们在写 shell 脚本时经常会遇到一些需要交互的操作,比如修改某个文件,或是使用 yum install ssh-keygen certbot --nginx 等操作时,需要输入一些指令如 "y", "Enter" 和其他的一些信息。

我们写脚本就是为了自动操作,怎么可以等命令执行一会之后在按个回车进行下一步呢?既然我知道接下来要输入什么命令,我告诉你你帮我输入了不就得了?

聪明tōu lǎn的我们想到了一些办法来避免这种无谓的等待,记录下来分享给大家

1. 自动化输入

1.1 输入单个指令

这里用 yum install 来进行演示 (假设不使用 -y 参数)

echo "y" | yum install wget

如果要求输入回车,可以使用 echo 指令的参数 -e + \n 进行操作

echo -e "\n" | yum remove wget
**`echo -e` 的小知识**

若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:
\a 发出警告声;
\b 删除前一个字符;
\c 最后不加上换行符号;
\f 换行但光标仍旧停留在原来的位置;
\v 与\f 相同;
\n 换行且光标移至行首;
\r 光标移至行首,但不换行;
\t 插入 tab 符号;
\\ 插入 '' 字符;
\nnn 插入 nnn(八进制)所代表的 ASCII 字符;

1.2 输入多行指令

输入多行指令我们需要借助输入重定向操作符 <<

以下面这个脚本为例

#!/bin/bash

read -p "enter number:" no
read -p "enter name:" name
echo "you have entered $no, $name"

借助 << 符号进行自动化输入

#!/bin/bash
sh multi.sh << EOF
1
mutoe
EOF

但是有时候这种方法并不生效,比如 ssh-keygen 命令,那只有借助强大的 expect 命令了

1.3 借助 expect 进行交互

在使用 expect 前需要进行安装,方法很简单,以 CentOS 为例,只需要运行 yum install -y expect 即可

expect 有两种用法,一种是直接写 expect 解释器的脚本,和 bash 类似,以 #!/usr/bin/expect 开头

下面是一个合格的 expect 脚本示例

#!/bin/expect

set IP     [lindex $argv 0] # 读取第1个参数设置为 IP 变量
set PASSWD [lindex $argv 1] # 读取第2个参数设置为 PASSWD 变量
set CMD    [lindex $argv 2] # 读取第3个参数设置为 CMD 变量

spawn ssh $IP $CMD # spawn 来给命令加壳,以便于断言输出
expect { # expect 是断言命令
  # 如果读取到屏幕上输出 (yes/no) 信息,则输入 "yes" 并按下回车键
  # exp_continue 是继续等待花括号内的断言, 如果不加这一句会直接跳出 expect
  "(yes/no)?" { send "yes\r"; exp_continue }

  "password:" { send "$PASSWD\r" } # 如果读取到屏幕上输出 password 信息,则输入 PASSWD 变量中的内容
  "*host " { exit 1 } # 如果读取到 "No route to host" 等内容, 就以非0状态退出
}
expect eof # 等待命令执行结束

需要注意的是,在 expect 解释器内, 除了几个特定关键字的命令,其他命令都不可用,这种方式适用于执行命令较少,单次需要交互较多的自动化脚本

第二种用法是在 bash 脚本中执行 expect 配合重定向操作符, 在有大量脚本需要执行的情况下推荐使用该方式

下面是我在 certbot 命令时使用的 shell 脚本,以供参考

#!/bin/bash

sudo expect << EOF
spawn certbot --nginx
expect {
  "Enter email address" { send "mutoe@foxmail.com\n";exp_continue}
  "Please read the Terms of Service" {send "A\n";exp_continue}
  "Would you be willing to share your email address" {send "N\n";exp_continue}
  "Which names would you like to activate HTTPS for" {send "\n";exp_continue}
  "You have an existing certificate that has exactly the same domains" {send "1\n";exp_continue}
  "Please choose whether or not to redirect HTTP traffic to HTTPS" {send "2\n";exp_continue}
  eof
}

2. 修改文件

2.1 在文件中增加内容

我们想要将某个命令的输出写入到文件中进行保存,比如日志、新增一行配置,可以借助输出重定向符号 > >> 来实现

who > log.txt # > 符号将会先清空 log.txt 然后以 who 的输出写入到文件中
echo "append" >> log.txt # >> 符号会追加字符串 "append" 到文件的尾行

那如果需要写入多行该怎么办呢?虽然也可以借助 echo -e + \n 来实现,但是我们还有其他更优雅的办法

借助 cat 命令配合 << 符号也可以达到我们的目的

cat > log.txt << EOF
我有很多行
很多行
行
EOF

WHY?
cat 命令如果不接受任何参数,将会进入交互式界面,输入什么就会输出什么;
配合 > 符号将 cat 的输出写入到文件 log.txt 中;
而 << 我们前面介绍过,会将多行输入重定向到前面的命令 cat 中

2.2 修改文件的内容

关于修改文件的内容,如何在不借助 vim 等工具情况下进行呢?

有请我们强大的 sed 命令登场!!

sed [选项] 指令 文件

其中选项有

  • -n 忽略没有修改的内容
  • -i 原地修改文件而不输出
  • -r 拓展正则表达式

指令为一个字符串,由 2 个部分组成 条件 命令,条件用于约束,指令进行操作

一个正常的替换命令长这样

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 配置片段为例

user nginx;
worker_processes  1;

http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;

  #gzip  on;

  include /etc/nginx/conf.d/*.conf;
}

# delete me

首先我们将 nginx 的启动用户改为自定义用户

sed -i "1c user mutoe;" /path/to/nginx.conf

-i 意思是将输出 "in-placed" 直接替换文件内容而不是作为输出
"1c user mutoe;" 是指将第 1 行替换(c)为"user mutoe;"

接下来我们去除 #gzip on; 前的空格,难度在于我们并不知道改行配置位于哪一行,没关系,我们借助正则表达式先找到这一行

sed -i "/#gzip\s+on;/s/#//" /path/to/nginx.conf

最后我们删除文件的最后一行

sed -i "$d" /path/to/nginx.conf

好了,所有内容到这里就结束啦,如果看的不过瘾,这里有我在实际使用中的一些脚本,以供参考。

如果你有任何疑问或是支持,欢迎在下方留言。

参考资料

 

转自:https://github.com/mutoe/blog/blob/master/source/_posts/interactive-command-in-shell.md

扫描二维码推送至手机访问。

版权声明:本文由满纸空言发布,如需转载请注明出处。

本文链接:https://mzky.cc/post/7.html

标签: shellLinux
分享给朋友:

“在 Shell 脚本中进行交互的一些心得” 的相关文章

红旗11系统下载3年前 (2021-07-09)
go语言优秀的框架3年前 (2021-07-19)
锻炼算法3年前 (2021-09-01)

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。