Úplné bash
řešení. Ukažte, jak snadno analyzovat další záhlaví, aniž by bylo vyžadováno 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
Produkce:
302
GFE/2.0
text/html; charset=UTF-8
Podle RFC-2616 jsou hlavičky HTTP modelovány tak, jak je popsáno v "Standard pro formát internetových textových zpráv ARPA" (RFC822), který jasně uvádí oddíl 3.1.2:
Název pole se musí skládat z tisknutelných znaků ASCII (tj. znaků, které mají hodnoty mezi 33 a 126, desítkové, kromě dvojtečky). Tělo pole může být složeno z libovolných znaků ASCII, kromě CR nebo LF. (I když CR a/nebo LF mohou být přítomny ve skutečném textu, jsou odstraněny rozbalením pole.)
Výše uvedený skript by tedy měl zachytit jakékoli záhlaví vyhovující RFC-[2]822 s významnou výjimkou složených záhlaví .
Pokud byste chtěli extrahovat více než pár hlaviček, mohli byste všechny hlavičky nacpat do asociativního pole bash. Zde je jednoduchá funkce, která předpokládá, že jakákoli daná hlavička se vyskytuje pouze jednou. (Nepoužívejte jej pro Set-Cookie
; viz níže.)
# 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")
}
Příklad:
$ 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
Všimněte si, že odpověď SO obsahuje jeden nebo více souborů cookie v Set-Cookie
záhlaví, ale můžeme vidět pouze poslední, protože naivní skript přepisuje položky se stejným názvem záhlaví. (Stává se, že byl jen jeden, ale to nemůžeme vědět.) I když by bylo možné rozšířit skript na speciální případ Set-Cookie
, lepší přístup by pravděpodobně bylo poskytnout soubor cookie-jar a použít -b
a -c
možnosti curl, aby se to zachovalo.