【问题标题】:search a word in next lines after a first word has been found在找到第一个单词后在下一行中搜索一个单词
【发布时间】:2017-04-08 00:17:57
【问题描述】:

我们以这个文件textfile.txt为例:

foo
bar
foo
bar
foo**word1**bar
foo
bar**word2**foo
foo
foo
bar
foo**word1**bar
foo
foo
bar**word2**foo
foo
foo
bar
foo**word1**bar
foo
bar**word2**foo
foo
bar
foo**word1**bar
foo
bar
foo
bar
bar**word2**foo
foo

我要做的是:在文件中搜索第一个单词,这里的单词是**word1**,如果找到了这个单词,在同一行搜索第二个单词,这里我是**word2**

我尝试使用grep 搜索**word1**,并使用-n 选项来获取行号。然后用这个行号,用sed提取匹配的行和接下来的两个,然后再做一个grep来搜索**word2**。它还应该每次匹配**word1****word2**

但感觉这不是实现这一目标的最佳方式。

在这个例子中,应该有 3 个正匹配:最后一个不起作用,因为 **word2****word1** 提前 4 行,我希望最多提前 2 行。

关于 awk 的输出,我想输出两个单词匹配的行号,以及找到它们的相应行。

我还有一个返回输出的 shell 脚本。我想做的是:对于每个匹配的单词,打印"my_script_result" + "awk_result" > file

【问题讨论】:

  • but it doesn't feel like it's the best way to do this 是的,awk 会是更好的选择
  • 还有你想对匹配的行做什么?只是打印它们还是进一步处理?
  • 对不起,我忘了精确:我想做进一步的处理(打印匹配的行、行号和其他信息到文件)。我尝试了 awk,一开始它看起来更简单,但由于我是在 shell 脚本中执行的,所以我没有找到在我的 shell 脚本中使用 awk 结果的正确方法
  • 我已投票结束此问题,因为它似乎是请求推荐工具或解决方案,而不是请求帮助您自己的代码。这使您的问题与 StackOverflow 无关。如果该评估不正确,并且您确实需要帮助编写自己的代码,那么请add your work so far to your question,我很乐意撤回我的近距离投票。

标签: unix sed grep


【解决方案1】:

这个 awk 单行代码可能会有所帮助:

awk '/word1/{ok=1}ok && /word2/{print NR,$0}' file

在上面的行中,/word1/ 是您的第一个单词,/word2/ 是您的第二个单词。输出将是匹配的行号和匹配的行。

它是这样工作的:

脚本从文件开头读取行,一旦找到word1,设置变量ok =1 (true)。第二部分检查ok AND word2 matched,如果满意,打印输出。因此,如果word2 在我们发现word1 之前匹配,okfalse,则将跳过该行。

根据OP的更新编辑:

awk /word1/{ok=1;s=NR}ok && NR<=s+2 && /word2/{print NR,$0}' file
7 bar**word2**foo
20 bar**word2**foo

【讨论】:

  • 如果同一个文件中有多个单词匹配,它是否也有效?例如 3 对 word1 / word2 在同一个文件中。另外,由于我想添加一些来自带有 awk 输出的 shell 脚本的信息,有没有办法例如在每次找到这两个单词时得到类似 "shell_script_output" + "awk_output" &gt; file 的东西?
  • 另外,我指定我只想在**word1** 之后的下一行中找到**word2**。在您的脚本中,我认为即使 **word2** 位于文件的后面,它也会匹配。
  • @Whin3 你能做一个更好的例子,它包含你所有的需求案例,也提供所需的输出。否则会有更多的砰砰声。
  • 对不起,如果不清楚,我试图解释得更好。
  • @Whin3 如果三行:#1:word1, #2:word2 #3 word2 那你想要什么?
【解决方案2】:

从标记的工具中选择 sed:

echo shelloutput && sed -En "/word1/{/word2/{=;p;};N;/word2/{=;p;};N;s/^.*\n//;/word2/{=;p;};N;s/^.*\n//;/word2/{=;p;}}" EgrepToy.txt

输出:

shelloutput
7  
bar**word2**foo  
14  
bar**word2**foo  
20  
bar**word2**foo  

像这样工作:

  • 创建一些输出echo shelloutput
  • 直接继续sed&amp;&amp;
  • 寻找第一个字/word1/{
  • 寻找第二个字/word2/{
  • 有条件打印行号并找到行=;p;};
    • 获取下一行N;
    • 删除第一个模式空间行,包括换行符,不终止s/^.*\n//;
    • 寻找第二个字/word2/{
    • 打印行号=;
    • 打印匹配线p;
  • 字面上重复两次

如果您想要两个匹配项,即只为 word2 扫描以下两行,则只重复一次,只需删除一个 N;s/^.*\n//;/word2/{=;p;};

【讨论】:

    【解决方案3】:

    从标记工具中选择 grep:

    echo shelloutput && grep -nA2 "word1" EgrepToy.txt | egrep "word2"
    

    输出:

    shelloutput  
    7-bar**word2**foo
    20-bar**word2**foo
    

    由于我不确定我是否正确理解“在此示例中,应该有 3 个正匹配”(我认为 OP 和我以某种方式计算“下一行”的方式不同),我添加了一个替代方案来获得三个:

    echo shelloutput && grep -nA3 "word1" EgrepToy.txt | egrep "word2"  
    

    输出:

    shelloutput  
    7-bar**word2**foo  
    14-bar**word2**foo  
    20-bar**word2**foo  
    

    两种解决方案的工作原理基本相同:

    • 创建所需的shell输出echo shelloutput
    • 立即继续 grep &amp;&amp;
    • grep 第一个单词egrep word1
    • 在输出-A2 中包含正确数量的以下行
    • 添加输入文件行号-n
    • grep 第二个单词的结果| egrep word2

    回显 shelloutput 是你想做的任何事情的占位符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-17
      • 2013-12-18
      • 2021-05-30
      • 1970-01-01
      相关资源
      最近更新 更多