Bash:从HTTP响应中删除标头

时间:2013-11-24 19:09:12

标签: regex perl bash sed grep

如果我有一些包含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>

这个文本是从一个命令输入的,如何删除标题只留下身体?

(在标题中,\r\n用作换行符。\r\n\r\n标记标题的结尾和正文的开头。)

以下是我尝试的内容(...表示任何命令,例如catcurl,它会将一些HTTP标头和正文输出到标准输出):

SED

我的第一个想法是使用sed进行替换,以便在第一次出现\r\n\r\n之前删除所有内容:

... | sed 's|^.*?\r\n\r\n||'

但这不起作用,主要是因为sed仅对各行进行操作,因此无法在\r\n上运行。 (此外,它不支持?非贪婪的运算符。)

的grep

我还考虑过将grep\r\n\r\n一起使用... | grep -oP '(?<=\r\n\r\n).*'

grep

但这也不起作用(主要是因为pcregrep仅对各行进行操作)。

-M有一个多线模式(pcregrep),但perl通常不可用(默认情况下不会在Ubuntu 12.04,Mac OS X 10.7等中安装),而我我想要一个不需要任何非标准工具的解决方案。

perl的

然后我考虑使用/s代替.,以便... | perl -pe 's/^.*?\r\n\r\n//s' 匹配换行符:

$/

我认为这更接近于一个有效的解决方案。但是,我认为Perl的输入记录分隔符(\n)默认为\r\n,需要更改为.,以便\r\n可以匹配-0$/选项可用于将... | perl -pe '$/ = "\r\n"; s/^.*?\r\n\r\n//s' 设置为单个字符,但不能设置为多个字符。我试过这个,但我不认为这是正确的:

^

另外,我认为\r\n\r\n匹配“行首”,但需要匹配“文件开头”。

偏移和子串

我想知道BodyOffset=$(expr index "$MyHttpText" "\r\n\r\n") 的偏移使用:

HttpBody=${MyHttpText:BodyOffset}

然后使用:

将主体提取为子串
expr

不幸的是,index的Mac OS X版本不支持#。另外,如果可能的话,我想要一个不需要创建变量的解决方案。

参数替换

我的另一个想法是使用参数替换,其中$MyHttpText表示“从*\r\n\r\n中移除与$MyHttpText的前端匹配的HttpBody=${MyHttpText#*\r\n\r\n} 的最短部分” :

{{1}}

但是我不知道如何在一个管道序列的命令中使用它,而且我更喜欢一个不需要变量的解决方案。

5 个答案:

答案 0 :(得分:8)

可以做到这一点:

sed '1,/^$/d' data.txt

此命令删除从第1行开始的所有内容,并在第一次出现空行(^$)时结束。如果您将\n作为换行符,则此方法有效。如果您有\r\n作为换行符,则可以使用dos2unixunix2dos来回转换它们,也可以将\r字符添加到 } regex:

sed '1,/^\r$/d' data.txt

但是,最后一行仅在\r\n作为换行符时才有效,为了使其适用于两种类型的换行符,您可以使用:

sed '1,/^\r\{0,1\}$/d' data.txt

这里我们正在寻找一个带有0或1个\r字符的空行。

答案 1 :(得分:2)

你的Perl单行命令没有(不能)删除标题,因为它当时只读取一行输入。您需要取消设置输入记录分隔符以将整个输入读取为一行。

perl -0777 ...

答案 2 :(得分:1)

在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

答案 3 :(得分:0)

... | perl -ne 'print if $after_header; $after_header = 1 if /^\r$/'

答案 4 :(得分:0)

除非指定-I选项(大写i)或-D(转储标题),否则

curl默认不会从bash返回标题。因此,在你的卷发电话中没有指定治疗方法!