我有一个包含文本和多个 URL 的字符串。如何使用 sed 提取一个特定 URL(特定域的 URL)?例如,我有这个:
Text foo bar Text foo bar <br /><br /> http://www.this.file <br />http://another.file <br />http://mine.com/this.html <br />http://myURL.net/files/IWANTthis <br />http://www.google.com/thisnot
并sed
应返回以下内容:
http://myURL.net/files/IWANTthis
答案1
在特殊情况下,sed 可能会出现一些问题。正如许多地方所建议的那样(例如)- 不使用正则表达式,而是使用 html 解析器引擎。纯文本浏览器 lynx(可在任何 Linux 上使用)中包含一个此类易用的解析器。然后,您只需使用 grep 提取所需的 URL。
lynx -dump -listonly myhtmlfile.html | grep IWANTthis | sort -u
但是,这不适用于损坏的 html 文件(无法正确解析)或带有链接的文本片段。另一种简单的方法是链接。如果您在名为 st3.txt 的文本文件中有一个类似的文本片段,您可以执行以下操作:
grep http ./st3.txt | sed 's/http/\nhttp/g' | grep ^http | sed 's/\(^http[^ <]*\)\(.*\)/\1/g' | grep IWANTthis | sort -u
解释:
grep http ./st3.txt => will catch lines with http from text file
sed 's/http/\nhttp/g' => will insert newline before each http
grep ^http => will take only lines starting with http
sed 's/\(^http[^ <]*\)\(.*\)/\1/g'
=> will preserve string from ^http until first space or <
grep IWANTthis => will take only urls containing your text of interest
sort -u => will sort and remove duplicates from your list
答案2
您可以使用grep
扩展正则表达式(正则表达式)为此:
grep -Eo '([-+.[:alnum:]]+://)?([-[:alnum:]]+.)*myURL.net(:[[:digit:]]+)?(/[[:graph:]]*)?' <<< '<input_string>'
命令各部分和正则表达式的解释:
grep -Eo
:我们有grep
两个选择。-E
: 使能够POSIX 扩展正则表达式。-o
:仅打印每行匹配的部分(若没有此选项,则grep
默认打印包含匹配部分的整行)。
'([-+.[:alnum:]]+://)?([-[:alnum:]]+.)*myURL.net(:[[:digit:]]+)?(/[[:graph:]]*)?'
:此正则表达式可能比您需要的更复杂一些,因此您应该简化或删除不必要的复杂部分。(复杂性是尝试提供通用解决方案的结果。)([-+.[:alnum:]]+://)?
:这符合方案URL 的末尾。?
末尾的指定匹配一次或根本不匹配(因此myURL.net
即使没有预先添加方案也会匹配)。我们包含略微不寻常的字符是-+.
因为RFC 3986指定“方案名称由以字母开头的字符序列组成,后跟字母、数字的任意组合,加号 ('+')、句号 ('.') 或连字符 ('-')“(重点是我的)。如果你确定总是http://
会出现在前面myURL.net
,那么你可以用简单的替换正则表达式的这一部分http://
。([-[:alnum:]]+.)*
:这匹配子域名。*
末尾的 指定匹配零次或多次(以便匹配像a.b.
in 这样的子域a.b.myURL.net
)。我们包含连字符 (-
),因为RFC 1035指定“[子域标签] 必须以字母开头,以字母或数字结尾,并且内部字符只能为字母、数字和连字符“(重点是我的)。如果您确定不需要匹配子域,那么您可以删除正则表达式的这一部分。myURL.net
:这是文字字符串的直接匹配myURL.net
。(:[[:digit:]]+)?
:这匹配任何端口指定如果它包含在 URL 中。(/[[:graph:]]*)?
:这与 URL 的其余部分匹配。[:graph:]
匹配任何可见字符。
<<< '<input_string>'
:我们grep
使用一个这里是字符串. (echo '<input_string>' |
是常见的选择。)
例子:
$ grep -Eo '([-+.[:alnum:]]+://)?([-[:alnum:]]+.)*myURL.net(:[[:digit:]]+)?(/[[:graph:]]*)?' <<< 'Text foo bar Text foo bar <br /><br /> http://www.this.file <br />http://another.file <br />http://mine.com/this.html <br />http://myURL.net/files/IWANTthis <br />http://www.google.com/thisnot'
http://myURL.net/files/IWANTthis
再次强调,我上面给出的正则表达式可能过于复杂,无法满足您的需要。您应该根据自己的目的进行修改。下面这样简单的操作就可以了:
grep -Eo 'http://myURL.net(/[[:graph:]]*)?' <<< '<input_string>'
答案3
您可以使用:sed 's/<br\ *\/>/\n/g' html_file | grep myURL.net
输出:http://myURL.net/files/IWANTthis
基本上,我用<br />
换行符替换所有内容,然后用 grep 抓取相关行。
这并没有考虑到<br>
标签的所有可能的(html 允许的)变化,但它可以处理示例中的变化。
答案4
您可以使用 来解析文件中所有的 URL,sed
然后grep
查找匹配项。
sed "s/http/\nhttp/g" your.html | sed -n "s#\(.*\)\(http.*//[a-Z0-9./-]*[^a-Z/]\)\(.*\)#\2#p;" | grep IWANTthis
在第一遍中,sed
用前面的换行符替换所有 http,以便sed
在第二遍中更容易地sed
提取 URL。这个正则表达式通常对我有用,但您可能需要对其进行调整以满足您的需求。
注意:您可以一次性完成此操作,但由于神秘性较强,很少使用的sed
命令可能难以维护,因此会变得复杂。