【问题标题】:Bash: Remove headers from HTTP responseBash:从 HTTP 响应中删除标头
【发布时间】:2013-12-09 09:14:45
【问题描述】:

如果我有一些包含 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 通常不可用(默认情况下未安装在 Ubuntu 12.04、Mac OS X 10.7 等中),我想要一个解决方案不需要任何非标准工具。

perl

然后我想到用perl 进行替换,使用/s 修饰符以便. 匹配换行符:

... | perl -pe 's/^.*?\r\n\r\n//s'

我认为这更接近于可行的解决方案。不过我觉得Perl的Input Record Separator($/)默认是\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 的 Mac OS X 版本不支持 index。另外,如果可能的话,我想要一个不需要创建变量的解决方案。

参数替换

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

HttpBody=${MyHttpText#*\r\n\r\n}

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

【问题讨论】:

    标签: regex perl bash sed grep


    【解决方案1】:

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

    perl -0777 ...
    

    【讨论】:

    • 这行得通!非常感谢您阐明在这种情况下正确使用输入记录分隔符。
    【解决方案2】:

    可以这样做:

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

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

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

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

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

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

    【讨论】:

    • 当行尾为\r\n时,这也有效吗?
    • 它需要一些调整,但它可以工作。看我的回答。
    • 可爱的解决方案,非常感谢!我之前没有使用过sed 的删除功能d,但是我可以看到这是使用它的完美情况。 Mac OS X 使用sed 的BSD 版本,它不理解\r 转义序列,但是可以使用$'\r' 来解决这个问题。所以sed '1,/^'$'\r''$/d' 适用于 Mac 和 Ubuntu。
    • 如果您使用fish,则语法为:sed '1,/^'\r'$/d'
    • 为了同时使用\r\n\n,您可以使用命令tr -d '\r' &lt; data.txt | sed '1,/^$/d'
    【解决方案3】:
    ... | perl -ne 'print if $after_header; $after_header = 1 if /^\r$/'
    

    【讨论】:

      【解决方案4】:

      在 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
      

      【讨论】:

        【解决方案5】:

        curl 默认情况下不会从 bash 返回标头,除非您指定 -I 选项(大写 i)或 -D(转储标头)。所以在你的 curl 调用中没有指定这些方法!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-13
          • 1970-01-01
          • 2011-07-05
          • 2013-04-26
          • 2017-01-18
          • 2011-12-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多