如何封装交互式程序为支持管道的非交互式脚本?附passphrase2pgp实践
通用方案:将交互式TUI程序封装为非交互式批处理脚本
核心逻辑
要实现从stdin接收输入、仅向stdout输出目标内容的封装,关键要解决两个问题:自动响应程序的交互式提示,以及过滤掉无关输出只保留需要的内容。
一、用Expect处理交互式输入
Expect是处理交互式程序的标准工具,针对你的场景,需注意避开终端接管的坑,同时精准匹配提示并发送输入:
- 禁用
interact命令,避免管道输入时脚本异常退出 - 从stdin读取输入内容(而非硬编码),适配管道传参
- 匹配程序的密码提示文本,自动发送读取到的密码
示例脚本(my-keygen)
#!/usr/bin/expect -f # 读取stdin中的密码,去除末尾换行符 set passphrase [read stdin] regsub {\n$} $passphrase "" passphrase # 启动目标程序 spawn passphrase2pgp # 匹配密码提示并发送 expect "Enter passphrase:" send "$passphrase\r" # 处理确认密码的提示(如果有) expect "Confirm passphrase:" send "$passphrase\r" # 等待程序执行完毕,捕获所有输出 expect eof # 过滤并输出armored格式的私钥 set full_output [exp_out] # 正则匹配PGP私钥块 if {[regexp {-----BEGIN PGP PRIVATE KEY BLOCK-----.*?-----END PGP PRIVATE KEY BLOCK-----} $full_output target_key]} { puts $target_key }
二、脚本配置与测试
- 赋予执行权限:
chmod +x my-keygen
- 管道调用测试:
printf "your-password" | ./my-keygen | gpg --import
三、通用适配指南
针对其他交互式程序(如ssh-keygen),只需调整以下3个部分:
- 提示匹配规则:比如
ssh-keygen会提示Enter file in which to save the key、Enter passphrase,对应修改expect后的字符串 - 输出过滤规则:如果是SSH私钥,匹配
-----BEGIN RSA PRIVATE KEY-----到-----END RSA PRIVATE KEY-----的内容 - 输入发送逻辑:根据程序需要的输入项,依次发送对应内容(比如
ssh-keygen需要跳过文件名提示,可发送\r)
四、常见问题排查
- 管道输入导致脚本提前退出:绝对不要用
interact,改用read stdin读取输入,确保输入流被正确处理 - 输出包含多余提示:用正则精准匹配目标输出块,只输出匹配结果,过滤掉程序的交互提示、日志等
- 程序检测终端环境拒绝执行:在
spawn前添加set env(TERM) vt100,模拟终端环境绕过检测
内容的提问来源于stack exchange,提问作者luochen1990
相关产品推荐
相关产品推荐

