如何通过 /bin/sh 解析 HTTP headers?

How to parse HTTP headers by /bin/sh?

这里 - 在 bash 中有一个非常优雅的解析解决方案,无需 awk:

shopt -s extglob # Required to trim whitespace; see below

while IFS=':' read key value; do
    # trim whitespace in "value"
    value=${value##+([[:space:]])}; value=${value%%+([[:space:]])}

    case "$key" in
       Server) SERVER="$value"
               ;;
       Content-Type) CT="$value"
               ;;
       HTTP*) read PROTO STATUS MSG <<< "$key{$value:+:$value}"
               ;;
    esac
done < <(curl -sI http://www.google.com)
echo $STATUS
echo $SERVER
echo $CT

但是如何将其转换为纯 sh?

我也打算使用 wget 而不是 curl,但似乎我可以处理。

如果你没有 extglob,你可以 trim 空格

set -- $value
value=$*

这也会压缩字段内部的空白,但在这种情况下似乎无害。它还将执行通配符扩展,这是一个更讨厌的问题; set -f 可以解决这个问题,如果你可以使用的话。

但是,也许最简单的解决方案是通过管道传输到分配变量的简单 Awk 脚本,这样您就可以 eval 它们。

eval $(curl -sI http://www.google.com |
    awk -v q="'" '{ gsub(/\r/, ""); gsub(q, q "\"" q "\"" q); }
        /HTTP\// { print "PROTO=" q  q; 
            print "STATUS=" q  q; print "MSG=" q  q; next }
        /^Server: / { ="SERVER=" q; $NF = $NF q; sub(q " ", q); print; next; }
        /^Content-Type: / { ="CT=" q; $NF = $NF q; sub(q " ", q); print; next; }')

单引号应该足以确保 eval 是安全的,尽管我确信空格处理可能更可靠。

这是用 heirloom-sh 测试的。它应该适用于您找到的任何 bourne shell:

(curl -I -s http://www.example.com;echo)| (
read HTTP_VAR_PROTO HTTP_VAR_STATUS HTTP_VAR_MSG
while IFS=': ' read -r key value; do
    case "$key" in
       Server) HTTP_VAR_SERVER="$value"
               ;;
       Content-Type) HTTP_VAR_CONTENT_TYPE="$value"
               ;;
       '')
        set #remove "set" and put your script here
        ;;
    esac
done
)

我在设置变量前加上 HTTP_VAR_ 前缀,以避免让 HTTP 响应覆盖环境的重要部分。你必须把你的脚本 inside case,但没有办法(不使用外部程序或 evaling 输入)得到 read 在 bog-standard bourne 中以你想要的方式工作。

您可以 trim 空格,方法是在此处文档中使用 read。使用命名管道 "simulate" 进程替换。 (进程替换实际上可以在某些操作系统上使用命名管道实现。)

mkfifo headers
curl -sI http://www.google.com > headers &

{
  # This line is guaranteed to be first, before any headers.
  # Read it separately.
  read -r PROTO STATUS MSG
  while IFS=':' read -r key value; do
      # trim whitespace in "value"
      read -r value <<EOF
$value
EOF

      case $key in
         Server) SERVER="$value"
                 ;;
         Content-Type) CT="$value"
                 ;;
      esac
  done
} < headers
rm headers

我把它留作练习,研究如何正确缩进此处文档的正文。