我正在尝试使用 sed 提取 URL 查询字符串中众多键值对之一的值部分
这就是我正在尝试的:
echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's@^https?://(www.)?youtube.com/(watch\\?)?.*?v(=|/)([a-zA-Z0-9\-_]*)(&.*)?$@$4@'
但它总是按原样输出输入的 URL。
我究竟做错了什么?
更新 1
澄清一些问题:
- 正则表达式比它应该的要复杂得多,因为我还试图检查输入的有效性,并且只有输入有效时才生成输出。因此匹配更严格。
- 所需的输出是查询字符串中键“v”的值。
- 无法找到
sed
我正在使用的版本,但它是 Mac OS X(10.7.5)附带的版本。 - 在我的版本中,
sed
$1、$2 等似乎匹配,而 \1、\2 等则出现错误:sed: 1: "s@^https?://(www.)?yout ...": \4 not defined in the RE
不正确!这是我后来发现的。抱歉造成混淆。
更新 2
已根据下面@slhck 的建议更新sed
RE 以使其更加具体,但问题仍然存在。
更新 3
根据man
此版本的页面,sed
看来这是一个 BSD 风格的版本。
答案1
更简单,如果你只想要abc
:
echo 'http://www.youtube.com/watch?v=abc&g=xyz' | awk -F'[=&]' '{print $2}'
如果你想要xyz
:
echo 'http://www.youtube.com/watch?v=abc&g=xyz' | awk -F'[=&]' '{print $4}'
解释:
awk
: 是一种脚本语言,可自动逐行处理输入文件,并将每行拆分为字段。因此,当您使用 处理文件时awk
,对于每行,第一个字段为$1
,第二个字段为$2
,依此类推,直到$N
。默认情况下awk
使用空格作为字段分隔符。-F'[=&]'
:-F
用于将字段分隔符从空格更改为其他内容。在本例中,我给它一个_班级_ 个字符。许多语言都使用方括号 ([ ]
) 来表示字符组。因此,具体来说,-F'[=&]'
意味着awk
应该同时使用&
和=
作为字段分隔符。因此,给定您问题的输入字符串,使用
&
和=
作为分隔符,awk
将读取以下字段:http://www.youtube.com/watch?v=abc&g=xyz |----------- $1 -------------| --- - --- | | | | | ̣----- $4 | -------- $3 ----------- $2
因此,您需要做的就是打印您想要的任何一个
{print $4}
。
您说您还想检查字符串是否是有效的 YouTube URL,但您无法这样做,sed
因为如果它与您提供的正则表达式不匹配,它只会打印整行。您可以使用类似这样的工具Perl
仅在正则表达式匹配时打印:
echo 'http://www.youtube.com/watch?v=abc&g=xyz' |
perl -ne 's/http.*www.youtube.com\/watch\?v=(.+?)&.+/$1/ && print'
最后,要进行简单的打印,abc
您可以使用标准 UNIX 工具cut
:
echo 'http://www.youtube.com/watch?v=abc&g=xyz' |
cut -d '=' -f 2 | cut -d '&' -f 1
答案2
如果你需要“xyz”,请尝试这个(GNU sed):
echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's/.*=\([[:alnum:]]*\).*/\1/'
答案3
如果您确实只想要视频 ID – 介于v=
和下一个之间的任何内容&
– 只需使用:
sed -r 's/.*v=([[:alnum:]]*).*/\1/'
您的命令出了以下问题:
需要
-r
使用扩展正则表达式。如果省略它,sed
则会按字面意思解释括号,因此不会有任何匹配组。对于 BSDsed
,请改用-E
选项。您使用
$1
来引用匹配,但您应该使用\1
。$1
例如,实际上是传递给当前脚本的 shell 参数。您应该使用字符类
[[:alnum:]]
(或[a-zA-Z0-9_]
取决于 ID 的设置方式)来匹配参数值,否则下一个参数值&
也将被捕获。正则表达式是贪婪的,只有abc&g=xyz
在您使用时才会匹配.*?
,因为 BRE/ERE 不支持惰性量化,只有 Perl 正则表达式或其他“现代”风格才支持。
答案4
它总是显示 URL,因为 SED 不匹配它。
echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's!^http://www.youtube.com/watch\?\(.*=.*\)&\(.*=.*\)!\1!'
将显示 v=abc