sed:提取 URL 查询字符串中键值对的值

sed:提取 URL 查询字符串中键值对的值

我正在尝试使用 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

澄清一些问题:

  1. 正则表达式比它应该的要复杂得多,因为我还试图检查输入的有效性,并且只有输入有效时才生成输出。因此匹配更严格。
  2. 所需的输出是查询字符串中键“v”的值。
  3. 无法找到sed我正在使用的版本,但它是 Mac OS X(10.7.5)附带的版本。
  4. 在我的版本中,sed$1、$2 等似乎匹配,而 \1、\2 等则出现错误: sed: 1: "s@^https?://(www.)?yout ...": \4 not defined in the RE 不正确!这是我后来发现的。抱歉造成混淆。

更新 2

已根据下面@slhck 的建议更新sedRE 以使其更加具体,但问题仍然存在。

更新 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则会按字面意思解释括号,因此不会有任何匹配组。对于 BSD sed,请改用-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

相关内容