自动化终端程序的交互过程

交互式

有很多常见软件都是交互式进行处理的,因为它们可能有多个需要用户所定义的值要在运行时获得。这些值通常通过终端输入接收或者其它地方(比如 GUI 程序的编辑框)来获得,被当做变量使用或者根据其值作为执行不同计算逻辑的分支条件。

例如 Linux 上常见的 sudo 命令,当用户执行 sudo <sub_process>时,终端会接收用户输入的密码。还有 apt install <package_name>,会让用户输入 y 确认以后才会进行安装或输入 n 取消。这些都是典型的交互式处理的软件。

Expect

通常当你想程序化调用那些需要强制要求交互的程序时,不会那么方便。假设 apt 是没有 -y 参数的,也就是说你安装软件必须经过一次确认交互。这时候你想自动化完成软件的安装就会变得困难,因为默认情况需要人为参与,自动变成半自动。
所以,为了解决这些软件的交互麻烦,诞生了一个叫做 Expect 的程序。Expect 利用伪终端将子进程(例如上文提到的执行 apt 命令)包装起来,然后允许其它程序接入其终端进行输入。

自动完成 sudo 交互和 apt 交互进行软件安装 (mc):

#!/usr/bin/expect -f
          
          set password "my password"
          spawn sudo apt install mc
          expect {
          "*password*" { send "$password\r"; exp_continue }
          "*\[Y/n\]:" { send "y\r" }
          }
          

上面是一个 expect 脚本的例子,它可以通过正则表达式匹配输出让你处理不同的需要输入的情况。匹配到包含 “passwor for” 的字符串的时候肯定是 sudo 需要接收用户密码的情况,而包含 “[Y/n]” 则是 apt 在请求用户确认。

但是 expect 跟 bash 一样,语法支持有限,并且语法要求个人感觉更加恶劣:注意到 expect 右边的大括号了吗?这里没有什么大括号换行不换行的编程语言派别,而是你甚至不能删掉 expect 和左括号之间的空格,否则就是错误的语法。

不是简单情况我不想写 expect 脚本,因为它相比 bash shell 更加令我厌恶。但是 Expect 的想法是被提倡的,所以下面的内容还是跟 Expect 有关。

更复杂的交互过程

待更。