【发布时间】: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 标记标题的结尾和正文的开始。)
这是我尝试过的(... 表示任何命令,例如 cat 或 curl,它们会将一些 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}
但我不确定如何在管道命令序列中使用它,而且我更喜欢不需要变量的解决方案。
【问题讨论】: