【问题标题】:'grep +A': print everything after a match [duplicate]'grep +A':匹配后打印所有内容[重复]
【发布时间】:2013-08-12 13:23:43
【问题描述】:

我有一个包含 URL 列表的文件。如下所示:

文件1:

http://www.google.com
http://www.bing.com
http://www.yahoo.com
http://www.baidu.com
http://www.yandex.com
....

我想获取之后的所有记录:http://www.yahoo.com,结果如下:

文件2:

http://www.baidu.com
http://www.yandex.com
....

我知道我可以使用 grep 来查找 yahoo.com 所在的行号

grep -n 'http://www.yahoo.com' file1

3 http://www.yahoo.com

但我不知道如何在第 3 行之后获取文件。另外,我知道 grep -A 中有一个标志,打印匹配后的行。但是,您需要指定匹配后所需的行数。我想知道有什么办法可以解决这个问题。喜欢:

Pseudocode:

grep -n 'http://www.yahoo.com' -A all file1 > file2

我知道我们可以使用我得到的行号和wc -l 来获取 yahoo.com 之后的行数,但是......感觉很糟糕。

【问题讨论】:

    标签: bash sed awk grep


    【解决方案1】:

    sedgrep 更容易做到这一点。 sed 可以将其任何单字母命令应用于包含范围的行;这个的一般语法是

    START , STOP COMMAND
    

    除了没有任何空格。 STARTSTOP都可以是一个数字(意思是“行号N”,从1开始);一个美元符号(意思是“文件的结尾”),或者一个用斜杠括起来的正则表达式,意思是“与这个正则表达式匹配的第一行”。 (确切的规则稍微复杂一些;the GNU sed manual has more detail。)

    所以,你可以像这样做你想做的事:

    sed -n -e '/http:\/\/www\.yahoo\.com/,$p' file1 > file2
    

    -n 的意思是“除非特别告知,否则不要打印任何内容”,-e 指令的意思是“从与正则表达式 /http:\/\/www\.yahoo\.com/ 匹配的行的第一次出现到文件末尾,@ 987654334@rint。”

    这将在输出中包含带有http://www.yahoo.com/ 的行。如果您想要该点之后的所有内容而不是该行本身,最简单的方法是反转操作:

    sed -e '1,/http:\/\/www\.yahoo\.com/d' file1 > file2
    

    这意味着“从第 1 行到匹配正则表达式 /http:\/\/www\.yahoo\.com/ 的第一行,delete 行”(然后,隐式地打印其他所有内容;请注意,-n 不是 这次使用)。

    【讨论】:

    • 什么是 $p?好的,这是STOP。它什么时候停止?谷歌搜索一无所获。我看过的sed教程都没有提到。
    • @7stud 在我使用的术语中,STOP 只是美元符号; 'p' 是命令。 '/.../,$' 表示“从匹配正则表达式的第一行开始执行某些操作,一直持续到文件末尾”,而“p”表示“打印”。 gnu.org/software/sed/manual/html_node/Addresses.html 可能会有所帮助。
    • 'p' 是命令 -- 啊。为什么不写成:/../,$ p?,格式为START,STOP COMMAND
    • @7stud 如果你这样做是行不通的。好吧,我想现代实现可能已经放宽了语法,但是在 传统 Unix 版本 7 实现中,地址和命令之间不允许有空格。
    【解决方案2】:

    AWK

    如果您不介意使用AWK

    awk '/yahoo/{y=1;next}y' data.txt
    

    这个脚本有两个部分:

    /yahoo/ { y = 1; next }
    y
    

    第一部分说明如果遇到yahoo行,我们设置变量y=1,然后跳过该行(next命令会跳转到下一行,因此跳过当前行的任何进一步处理)。如果没有next 命令,将打印 yahoo 行。

    第二部分是以下的简写:

    y != 0 { print }
    

    这意味着,对于每一行,如果变量 y 不为零,我们将打印该行。在 AWK 中,如果您引用一个变量,该变量将被创建并且是零或空字符串,具体取决于上下文。在遇到 yahoo 之前,变量 y 为 0,因此脚本不打印任何内容。遇到yahoo后,y为1,之后的每一行都会被打印出来。

    Sed

    或者,使用 sed,以下将删除所有内容,包括使用 yahoo 行:

    sed '1,/yahoo/d' data.txt
    

    【讨论】:

    • 你能解释一下awk的语法吗?我的理解: /yahoo/ 使用正则表达式搜索该行,然后从该行开始,创建一个名为 y 的变量,然后将其值设置为 1,然后是否应该打印该行取决于 y 的值。然后每行都会在雅虎之后打印。我不太确定“下一个”命令
    • 我的错,我忘了解释。请查看我的更新。
    • 如果我理解正确,它应该是这样的: y=0 for line in file: if (/yahoo/): y=1 go to next line if (y!=1):打印线
    • 如果你也想包含http://www.yahoo.com的部分,你可以使用awk '/yahoo/{y=1}y' data.txt
    • @KoheiNozaki 或者简单地说:awk '/yahoo/,0' data.txt。如果您知道搜索字符串接近文件末尾,则使用 sed 打印剩余部分将使用 sed -n -e '/yahoo/,$p' data.txt
    【解决方案3】:

    这在 Perl 中最容易做到:

    perl -ne 'print unless 1 .. m(http://www\.yahoo\.com)' file
    

    换句话说,打印第 1 行和第一次出现该模式之间不是的所有行。

    【讨论】:

    • 它也有效。以前从不使用 Perl。 1 .. m(search) 是什么意思,语法看起来与其他编程语言不同。不太直截了当..
    • @user84771 这意味着从当前行号通过与该搜索匹配的行开始。通常搜索是/search/,但我不想逃避斜线。例如,您可以说 print if 1 .. /^$/ 以打印并包含一个空行。
    • 对于那些仍然觉得这种单行代码晦涩难懂的人来说,关键是范围运算符(双点)。在标量上下文中,范围运算符充当维持其自身布尔状态的触发器。此外,当它的操作数之一是常量(如上面的“1”)时,它与正在评估的输入的当前行号匹配。详情在这里:perldoc.perl.org/perlop.html#Range-Operators
    【解决方案4】:

    使用这个脚本:

    # Get index of the "yahoo" word
    index=`grep -n "yahoo" filepath | cut -d':' -f1`
    
    # Get the total number of lines in the file
    totallines=`wc -l filepath | cut -d' ' -f1`
    
    # Subtract totallines with index
    result=`expr $total - $index`
    
    # Gives the desired output
    grep -A $result "yahoo" filepath
    

    【讨论】:

    • 你为什么要重新发明基本的sed one-liner?
    • 只是想用 grep 回答回答 grep 问题。
    • 这是非常有帮助的 user1502952.. 非常感谢!但似乎下次我有一个临时查询时,我会使用 sed 或 awk :)
    • 可能一个纯粹的 GNU grep 答案是 grep -Pzo '.*yahoo(.*\n)*' data.txt 或者本着脚本的精神,但是在一行中:grep -A$(wc -l < data.txt) yahoo data.txt
    【解决方案5】:
    awk '/yahoo/ ? c++ : c' file1
    

    打高尔夫球

    awk '/yahoo/?c++:c' file1
    

    结果

    http://www.baidu.com http://www.yandex.com

    【讨论】:

      猜你喜欢
      • 2018-08-29
      • 2012-09-22
      • 2017-04-02
      • 1970-01-01
      • 2011-07-17
      • 2011-03-12
      • 2019-08-30
      • 1970-01-01
      • 2017-02-01
      相关资源
      最近更新 更多