如何捕获含引号与环境变量的Bash命令输出?
我之前也碰到过类似的坑,尤其是用curl带一堆参数的时候,明明手动跑命令有输出,但用$(...)捕获后变量就空了,主要是这几个原因和对应的解决办法:
1. 确认命令输出的流向
你用了curl -v,这个参数会把调试信息输出到标准错误(stderr),而$(...)默认只捕获标准输出(stdout)。如果你的API响应确实在stdout,但命令执行出错(比如认证失败、URL解析错误)导致stdout为空,那变量自然是空的。
先直接运行你的curl命令,看看终端有没有实际的API响应输出。如果只有红色的调试信息,说明响应内容可能在stderr里,这时候可以把stderr重定向到stdout,让$(...)捕获所有内容:
OUTPUT="$(curl -v -u "${USER}:${PASSWD}" -X POST -H "Content-Type: application/json" -d '{ "xxx": true, "xxx2": "date" }' https://${ENV}/${ROOT}/api/try 2>&1)"
这里的2>&1就是把stderr(文件描述符2)的内容重定向到stdout(文件描述符1),这样所有输出都会被捕获到变量里。
2. 变量引用必须加双引号
你后续用echo $OUTPUT会导致shell对变量内容做分词、通配符扩展,哪怕变量里有内容,也可能因为空格、特殊字符被解析得看起来像空。一定要用双引号包裹变量:
echo "${OUTPUT}"
这样才能完整输出变量里的所有内容,包括换行、空格和特殊字符。
3. 检查命令中的变量与引号是否正确展开
你的curl命令里,-u ${USER}:${PASSWD}最好改成-u "${USER}:${PASSWD}"——如果USER或PASSWD里包含空格、@、!这类特殊字符,不加双引号会被shell错误解析,导致curl执行失败,自然没有输出。
另外,-d参数用单引号包裹JSON是对的,这样里面的双引号不会被shell解析;如果JSON里需要引用shell变量,那就要改用双引号并转义内部的双引号,比如:
-d "{ \"xxx\": true, \"xxx2\": \"${DATE}\" }"
4. 排查命令执行是否成功
捕获输出后可以检查命令的退出状态码,确认curl是否成功执行:
OUTPUT="$(curl ... 2>&1)" EXIT_CODE=$? echo "命令退出码: ${EXIT_CODE}" echo "${OUTPUT}"
curl的退出码非0就说明命令执行出错,这时候可以通过OUTPUT里的错误信息(因为已经重定向了stderr)排查问题,比如认证失败、连接超时等。
内容的提问来源于stack exchange,提问作者DenCowboy

