Bash: удаление заголовков из ответа HTTP
если у меня есть текст, содержащий HTTP-заголовки и тело, например:
HTTP/1.1 200 OK
Cache-Control: public, max-age=38
Content-Type: text/html; charset=utf-8
Expires: Fri, 22 Nov 2013 06:15:01 GMT
Last-Modified: Fri, 22 Nov 2013 06:14:01 GMT
Vary: *
X-Frame-Options: SAMEORIGIN
Date: Fri, 22 Nov 2013 06:14:22 GMT
<!DOCTYPE html>
<html>
<head>
<title>My website</title>
</head>
<body>
Hello world!
</body>
</html>
и этот текст передается из команды, как я могу удалить заголовки, чтобы оставить только тело?
(в заголовках, rn
используется в качестве разрыва строки. rnrn
отмечает конец заголовков и начало тела.)
вот что я пробовал (...
указывает любую команду, такую как cat
или curl
который выведет некоторые HTTP-заголовки и тело stdout):
sed
моей первой идеей было сделать замену с sed
, чтобы удалить все до первого вхождения rnrn
:
... | sed 's|^.*?rnrn||'
но это не работает, главным образом потому, что sed
работает только на отдельных линиях, поэтому он не может работать на r
или n
. (Кроме того, он не поддерживает ?
нежадный оператор.)
grep
я также думал об использовании grep
с положительным lookbehind для rnrn
:
... | grep -oP '(?<=rnrn).*'
но это тоже не работает (в основном потому, что grep
работает только на отдельных линиях).
pcregrep
имеет многострочный режим (-M
), но pcregrep
часто недоступен (он не установлен по умолчанию в Ubuntu 12.04, Mac OS X 10.7 и т. д.), И я хотел бы получить решение, которое не требует каких-либо нестандартных инструментов.
на Perl
я тогда подумал о замене perl
, С помощью /s
модификатор так что .
матчи разрывы строк:
... | perl -pe 's/^.*?rnrn//s'
я думаю, что это ближе к рабочим решением. Тем не менее, я думаю, что входной разделитель записей Perl ($/
) составляет n
по умолчанию, и должен быть изменен на rn
, так что .
может соответствовать rn
. The -0
опция может использоваться для установки $/
для одного символа, но не для нескольких символов. Я пробовал это, но я не думаю, что это правильно:
... | perl -pe '$/ = "rn"; s/^.*?rnrn//s'
кроме того, я думаю ^
совпадающие "старт строки", но должен соответствовать "началу файла".
смещение и подстроки
у меня была идея получить смещение rnrn
использование:
BodyOffset=$(expr index "$MyHttpText" "rnrn")
а затем извлечение тела в качестве подстроки с помощью:
HttpBody=${MyHttpText:BodyOffset}
к сожалению, Mac OS X версии expr
не поддерживает index
. Кроме того, если возможно, я хотел бы получить решение, которое не требует создания переменных.
замена параметра
один другая идея, которую я имел, заключалась в использовании подстановки параметров, где #
означает "удалить из $MyHttpText
самая короткая часть *rnrn
это соответствует передней части $MyHttpText
":
HttpBody=${MyHttpText#*rnrn}
но я не уверен, как использовать это в конвейерной последовательности команд, и снова я предпочел бы решение, которое не требует переменных.
5 ответов
sed можно сделать так:
sed '1,/^$/d' data.txt
эта команда удаляет все, начиная с строки 1 и заканчивая первым появлением пустой строки (^$
). Это работает, если у вас есть \n
как символ новой строки. Если у вас есть \r\n
в качестве символа новой строки вы можете использовать dos2unix
и unix2dos
чтобы конвертировать их туда и обратно, или вы можете добавить \r
символ sed регулярное выражение:
sed '1,/^\r$/d' data.txt
однако последняя строка будет только работать, если у вас есть \r\n
как символ новой строки, чтобы заставить его работать на обоих типах строк, вы можете использовать:
sed '1,/^\r\{0,1\}$/d' data.txt
здесь мы ищем пустую строку с 0 или 1 \r
символы.
ваша однострочная команда Perl не удаляет (не может) заголовки, потому что она читает только одну строку ввода в то время. Вам нужно отключить разделитель входных записей, чтобы прочитать весь вход как одну строку.
perl -0777 ...
также интересно делать в bash (только внутренние команды):
#!/bin/bash
while read LINE #<-- while you can read line from input
do #<-- do the following actions
if [ $FLAG ] #<-- if: this flag is set
then echo "$LINE" #<-- echo the input to output
elif [ ${LINE:0:1} = $'\r' ] #<-- else: if line starts with \r
then FLAG=true #<-- then raise the flag
fi
done
curl не возвращает заголовки по умолчанию из bash, если вы не укажете опцию-I (capital i) или-D (заголовки дампа). Поэтому сделайте cure ни один из них не указан в вашем вызове curl!