Bash脚本curl提取Location响应头时echo输出顺序错乱问题
问题原因
你看到的输出错位,核心原因是提取到的Location字段值末尾携带了回车符(\r,ASCII码0x0D):
- HTTP/1.x 协议规范明确要求,响应头的每一行必须以
CRLF(\r\n)作为行尾结束符,curl -I返回的原始响应头中,Location行的原始格式为Location: http://www.google.com/\r\n - 你的提取逻辑仅以
\n作为换行分割标识,awk提取第二列内容时,没有去掉行尾残留的\r,最终变量HTTP_HEADER_LOCATION实际存储的值是http://www.google.com/\r - echo执行打印时,输出完URL内容后遇到
\r字符,终端光标会直接跳回当前行的起始位置,后续打印的END内容会直接覆盖行首的前3个字符HTTP,最终呈现出END出现在行首的错位效果,并不是内容真的按乱序打印。
你可以通过以下命令直接验证变量里的隐藏\r字符:
echo "$HTTP_HEADER_LOCATION" | od -c
执行后就能看到输出内容末尾存在明确的\r标识。
修复方案
1. 快速修复当前Location提取逻辑
只需要在管道处理阶段去掉末尾的\r字符即可,任选一种写法:
- awk阶段直接处理掉回车符:
HTTP_HEADER_LOCATION=$(curl -I google.com 2>/dev/null | awk '/Location/ {sub(/\r$/,""); print $2}')
- 管道末尾加tr命令删除所有回车符:
HTTP_HEADER_LOCATION=$(curl -I google.com 2>/dev/null | grep Location | awk '{print $2}' | tr -d '\r')
2. 满足单次请求获取三类数据的需求
你最初提到需要单次请求同时拿到curl退出码、stderr输出、stdout输出,不要用多段管道的写法——管道内每个命令都是独立子进程,你无法直接拿到curl本身的正确退出码。推荐用临时文件分离输出的方案,稳定性最高:
#!/bin/bash # 创建临时文件存储两类输出 stderr_tmp=$(mktemp) stdout_tmp=$(mktemp) # 发起请求:-sS 静默模式但保留错误输出,-i 参数会将响应头和响应体共同输出到stdout curl -sS -i google.com 2>"$stderr_tmp" >"$stdout_tmp" curl_exit_code=$? # 此时三类数据已经全部获取,可直接用于后续处理: # - 命令退出码:$curl_exit_code # - stderr输出(含错误信息、协议相关提示):$(cat "$stderr_tmp") # - stdout输出(含响应头、HTML响应体):$(cat "$stdout_tmp") # 提取Location头 location=$(awk '/^Location:/ {sub(/\r$/,""); print $2}' "$stdout_tmp") echo "HTTP header location: START ${location} END" # 清理临时文件 rm -f "$stderr_tmp" "$stdout_tmp"
执行上述脚本后,你就能得到预期的正确输出:HTTP header location: START http://www.google.com/ END
内容的提问来源于stack exchange,提问作者slimdusty
相关产品推荐
相关产品推荐

