如何使用BashparsingHTTP标头?

我需要从我正在使用curl的网页头获得2个值。 我已经能够单独使用以下值:

response1=$(curl -I -s http://www.example.com | grep HTTP/1.1 | awk {'print $2'}) response2=$(curl -I -s http://www.example.com | grep Server: | awk {'print $2'}) 

但我不知道如何使用单个curl请求分别grep值:

 response=$(curl -I -s http://www.example.com) http_status=$response | grep HTTP/1.1 | awk {'print $2'} server=$response | grep Server: | awk {'print $2'} 

每一次尝试都会导致错误消息或空值。 我相信这只是一个语法问题。

Solutions Collecting From Web of "如何使用BashparsingHTTP标头?"

完整的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 

生产:

 302 GFE/2.0 text/html; charset=UTF-8 

根据RFC-2616 ,HTTP报头按照“ARPA因特网文本报文格式标准” (RFC822)中的描述进行建模,该报告清楚地说明了第3.1.2节:

字段名称必须由可打印的ASCII字符组成(即,值为33到126之间的十进制数,冒号除外)。 字段主体可以由除CR或LF以外的任何ASCII字符组成。 (虽然CR和/或LF可能出现在实际的文本中,但它们通过展开该字段的动作被移除。)

所以上面的脚本应该捕获任何符合RFC- [2] 822标准的头,除了折叠头以外

使用进程替换( <( ... ) ),您可以读入shell变量:

 sh$ read STATUS SERVER < <( curl -sI http://www.google.com | awk '/^HTTP/ { STATUS = $2 } /^server:/ { SERVER = $2 } END { printf("%s %s\n",STATUS, SERVER) }' ) sh$ echo $STATUS 302 sh$ $ echo $SERVER GFE/2.0 

如果你想提取多个标题,你可以把所有的标题放到一个bash关联数组中。 这是一个简单的函数,它假定任何给定的头只出现一次。 (不要将它用于Set-Cookie ;参见下文。)

 # Call this as: headers ARRAY URL headers () { { # (Re)define the specified variable as an associative array. unset $1; declare -gA $1; local line rest # Get the first line, assuming HTTP/1.0 or above. Note that these fields # have Capitalized names. IFS=$' \t\n\r' read $1[Proto] $1[Status] rest # Drop the CR from the message, if there was one. declare -gA $1[Message]="${rest%$'\r'}" # Now read the rest of the headers. while true; do # Get rid of the trailing CR if there is one. IFS=$'\r' read line rest; # Stop when we hit an empty line if [[ -z $line ]]; then break; fi # Make sure it looks like a header # This regex also strips leading and trailing spaces from the value if [[ $line =~ ^([[:alnum:]_-]+):\ *(( *[^ ]+)*)\ *$ ]]; then # Force the header to lower case, since headers are case-insensitive, # and store it into the array declare -gA $1[${BASH_REMATCH[1],,}]="${BASH_REMATCH[2]}" else printf "Ignoring non-header line: %q\n" "$line" >> /dev/stderr fi done } < <(curl -Is "$2") } 

例:

 $ headers so http://stackoverflow.com/ $ for h in ${!so[@]}; do printf "%s=%s\n" $h "${so[$h]}"; done | sort Message=OK Proto=HTTP/1.1 Status=200 cache-control=public, no-cache="Set-Cookie", max-age=43 content-length=224904 content-type=text/html; charset=utf-8 date=Fri, 25 Jul 2014 17:35:16 GMT expires=Fri, 25 Jul 2014 17:36:00 GMT last-modified=Fri, 25 Jul 2014 17:35:00 GMT set-cookie=prov=205fd7f3-10d4-4197-b03a-252b60df7653; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:00 GMT; path=/; HttpOnly vary=* x-frame-options=SAMEORIGIN 

请注意,SO响应在Set-Cookie标题中包含一个或多个Cookie,但是我们只能看到最后一个,因为无用脚本会覆盖具有相同标题名称的条目。 (碰巧,只有一个,但是我们不知道)。虽然可以将脚本扩展为特殊的Set-Cookie ,但更好的方法可能是提供一个cookie-jar文件,并使用-b-c卷曲选项为了维护它。