为何Shell脚本在Node.js中调用时行为不一致?
问题分析
原脚本的核心问题在于[ -t 0 ]的判断逻辑:在终端环境中,当没有输入时stdin是TTY设备,条件成立所以跳过base64;但Node.js的execFile调用时,stdin是一个未关闭的管道(而非TTY),此时! [ -t 0 ]为真,脚本会执行base64 -w 0,而base64会一直等待输入直到收到EOF,导致脚本卡住。
解决方案
我们需要替换TTY检测逻辑,改为直接检查stdin是否有可读数据,同时保证二进制数据(包括空字节)的处理兼容性。以下是修改后的脚本:
#!/bin/sh # 尝试非阻塞读取1字节,失败则说明无输入 if data=$(dd if=/dev/stdin bs=1 count=1 iflag=nonblock 2>/dev/null); then # 读取到数据,将已读字节和剩余stdin一起传给base64 printf "%s" "$data" | cat - /dev/stdin | base64 -w 0 else # 无输入,输出空 echo -n "" fi
代码解释
dd if=/dev/stdin bs=1 count=1 iflag=nonblock:用非阻塞模式读取1字节,若stdin无数据则立即失败返回非0状态码,避免无限等待。2>/dev/null屏蔽dd的错误输出(比如"Resource temporarily unavailable")。- 若读取成功,用
printf "%s" "$data"输出已读的1字节(避免echo处理二进制数据时的问题),再通过cat - /dev/stdin将其与剩余stdin数据合并,最后传给base64 -w 0转换。 - 若读取失败,直接输出空字符串,符合无输入时的需求。
验证说明
- 该脚本兼容POSIX sh(Alpine的busybox sh完全支持),无需额外软件。
- 支持包含空字节的二进制数据:dd和cat都是二进制安全的,不会截断或修改数据。
- 在终端和Node.js execFile调用场景下行为一致:无输入时立即退出,有输入时正常转换为base64输出。
内容的提问来源于stack exchange,提问作者Forivin
相关产品推荐
相关产品推荐

