为何脚本中使用空分隔符时printf退出码为1?
Bash脚本中
printf '%s\0%s\0'退出码为1的问题 我编写了一段Bash脚本,其中的printf '%s\0%s\0'命令退出码为1,即使强制使用Bash 5.2版本,结果依旧相同。
示例脚本
#!/usr/bin/env bash echo $BASH_VERSION set -x set -Eeuo pipefail function prompt_creds { local username password read -rp "username " username read -rsp "password " password printf '%s\0%s\0' "${username}" "${password}" } function main() { IFS=$'\0' read -r username password < <(prompt_creds ) echo "我的用户名是 ${username}" "我的密码是 ${password}" } main
脚本运行输出
./sample.sh 3.2.57(1)-release + set -Eeuo pipefail + main + IFS= + read -r username password ++ prompt_creds ++ local username password ++ read -rp 'username ' username username user ++ read -rsp 'password ' password password ++ printf '%s\0%s\0' user pass bash-5.2$ echo $? 1
命令行直接运行正常
bash-5.2$ IFS=$'\0' read -r u p < <(printf '%s\0%s\0' user pass) bash-5.2$ echo $u $p user pass
问题原因
核心问题在于read -r username password的行为:当它读取到两个以空字符分隔的字段(即输入的user和pass)后,会立即关闭输入管道,不再读取后续数据。而printf '%s\0%s\0'会输出user\0pass\0,最后那个额外的空字符会让printf尝试向已关闭的管道写入数据,触发SIGPIPE信号,导致printf异常退出。
在多数Bash环境中,被SIGPIPE终止的命令退出码为141(128+13,13是SIGPIPE的信号编号),你看到的退出码为1可能是环境差异或测试方式导致,但本质原因都是管道提前关闭引发的信号终止。
解决方法
修改printf的输出,去掉末尾多余的空字符,确保输出的内容刚好匹配read需要的两个字段:
printf '%s\0%s' "${username}" "${password}"
修改后,printf输出user\0pass,read读取完所有需要的数据后,管道正常关闭,printf可以正常退出,退出码为0,脚本也会执行到最后的输出语句。
内容的提问来源于stack exchange,提问作者Christian Bongiorno
相关产品推荐
相关产品推荐

