如何使用sed-awk-gawk显示匹配的字符串

时间:2011-02-24 18:41:48

标签: sed

我有一个名为'res'的文件,它是一行字符串中的29374个http数据字符。在它里面,有几个http链接,但我只想显示以'/ idNNNNNNNNN'结尾的那些,其中N是一个数字。事实上,我只对字符串'idNNNNNNNNN'感兴趣。 我试过了:

cat res | sed -n '0,/.*\(id[0-9]*\).*/s//\1/p'

但我得到了整个文件。 你知道办法吗?

4 个答案:

答案 0 :(得分:2)

perl -n -E 'say $1 while m!/id(\d{9})!g' input-file

应该有效。这恰好是9位数;那就是上面的{9}。您可以匹配8或9({8,9}),8或更多({8,}),最多9({0,9})等。

这项工作的例子:

$ echo -n 'junk jumk http://foo/id231313 junk lalala http://bar/id23123 asda' | perl -n -E 'say $1 while m!id(\d{0,9})!g'
231313
23123

当然,这是0到9的变体。

如果您遇到的是5.10之前的perl,请使用-e代替-Eprint "$1\n"代替say $1

工作原理

首先是Perl的两个命令行参数。 -n告诉Perl读取命令行上给出的标准输入或文件的输入,逐行,将$_设置为每一行。 $_是perl的很多东西的默认目标,包括正则表达式匹配。 -E只是告诉Perl下一个参数是Perl一行,使用新的语言功能(与-e不使用5.10扩展名。)

所以,看一个衬垫:say意味着打印出一些值,然后是换行符。 $1是第一个正则表达式捕获(捕获是由正则表达式中的括号进行的)。 while是一个循环结构,您可能熟悉它。 m是匹配运算符,!之后是正则表达式分隔符(通常,您在此处看到/,但由于该模式包含/,因此更容易使用否则,您不必将/转义为\/)。 /id(\d{9})是要匹配的正则表达式。请注意,分隔符为!,因此/并不特殊,它只与文字/匹配。括号形成一个捕获组,因此$1将是数字。 !是分隔符,后跟g,这意味着匹配尽可能多的次数(而不是一次)。这使得它获取行中的所有URL,而不仅仅是第一个。只要匹配,m运算符将返回一个真值,因此循环将继续(并运行say $1,打印出匹配)。

两步解决方案

认为这是仅使用sed执行此操作的一种方法。更复杂!

echo 'junk jumk http://foo/id231313 junk lalala http://bar/id23123 asda' | \
    sed 's!http://!\nhttp://!g' | \
    sed 's!^.*/id\([0-9]*\).*$!\1!' 

答案 1 :(得分:0)

cat res | perl -ne 'chomp; print "$1\n" if m/\/(id\d*)/'

答案 2 :(得分:0)

问题是sed和grep和awk在线上工作,而你只有一行。因此,您可能需要拆分,以便拥有多行 - 然后您可以使普通工具正常工作。

tr ':' '\012' < res |
sed -n 's%.*/\(id[0-9][0-9]*\).*%\1%p'

这会利用包含冒号的网址,并使用tr将冒号映射到换行符,然后使用sed选取任何斜线,然后选择id和一个或多个数字,后跟任何东西,并打印出id和数字字符串(仅)。由于这些只出现在URL中,因此它们每行只出现一个并且相对靠近行的起点。

答案 3 :(得分:0)

这是一个仅使用sed的一次调用的解决方案:

sed -n 's| |\n|g;/^http/{s|http://[^/]*/id\([0-9]*\)|\1|;P};D' inputfile

说明:

  • s| |\n|g; - 分而治之
  • /^http/{ - 如果模式空间以“http”开头
    • s|http://[^/]*/id\([0-9]*\)|\1|; - 捕获ID
    • P - 打印第一个换行符之前的字符串
  • }; - 结束如果
  • D - 删除第一个换行符之前的字符串,无论它是否包含“http”

修改

此版本使用相同的技术但更具选择性。

sed -n 's|http://|\n&|g;/^\n*http/{s|\n*http://[^/]*/id\([0-9]*\)|\1\n|;P};D' inputfile