【问题标题】:How can I use sed/awk/grep to print lines between the two identical words in a separate file?如何使用 sed/awk/grep 在单独的文件中打印两个相同单词之间的行?
【发布时间】:2020-08-05 11:25:03
【问题描述】:

我想打印两个模式之间的所有行,每个部分在一个单独的文件中。

图案:

ATOM  10185  O   WAT   622      86.629 114.783 125.073  1.00  0.00.  
ATOM  10186  H1  WAT   622      87.265 114.479 125.721  1.00  0.00.  
ATOM  10187  H2  WAT   622      86.215 115.543 125.482  1.00  0.00.  
TER  
ATOM  10188  O   WAT   623      84.441 115.565 126.663  1.00  0.00.  
ATOM  10189  H1  WAT   623      85.076 115.261 127.311  1.00  0.00.  
ATOM  10190  H2  WAT   623      84.027 116.325 127.071  1.00  0.00.  
TER  
ATOM  10191  O   WAT   624      85.591 117.441 124.690  1.00  0.00.    
ATOM  10192  H1  WAT   624      86.226 117.137 125.338  1.00  0.00.   
ATOM  10193  H2  WAT   624      85.176 118.201 125.098  1.00  0.00.   
TER

我想在新文件中包含的是:

文件1:

ATOM  10185  O   WAT   622      86.629 114.783 125.073  1.00  0.00.  
ATOM  10186  H1  WAT   622      87.265 114.479 125.721  1.00  0.00.  
ATOM  10187  H2  WAT   622      86.215 115.543 125.482  1.00  0.00.  
TER   

文件2:

ATOM  10188  O   WAT   623      84.441 115.565 126.663  1.00  0.00.  
ATOM  10189  H1  WAT   623      85.076 115.261 127.311  1.00  0.00.  
ATOM  10190  H2  WAT   623      84.027 116.325 127.071  1.00  0.00.  
TER  

等等

我尝试了我在网站和互联网上找到的所有内容,但最终没有得到我需要的东西。主要是如何在两种模式之间进行 grep,例如 patern1xxxxxpattern2,而不是将它们打印到文件中。 (sed or awk to print lines between wordshttps://unix.stackexchange.com/questions/264962/print-lines-of-a-file-between-two-matching-patterns/264977 和类似的)

我试过这个,但我收到错误awk: illegal statement at source line 1

awk '/TER/{n+=1}{print > "file_"n".txt"}'

谢谢

【问题讨论】:

  • 您打印的不是两个单词之间的文本块,而是以单词结尾的文本块。

标签: awk sed grep


【解决方案1】:

类似 BSD 的系统上的 man(1) awk 给出了这个答案:

/start/, /stop/
              Print all lines between start/stop pairs.


% cat 1.txt
l-2
l-1
TER1
l1
l2
l3
l4
l5
TER2
l6
l7

测试:

% awk '/TER1/, /TER2/' 1.txt 
TER1
l1
l2
l3
l4
l5
TER2

【讨论】:

  • 你能写出整个表达式吗?我必须说,我不经常使用 awk。我使用了与 sed -n '/TER/,/TER/p' file1 > file2 类似的东西,但我希望每个部分都在一个单独的输出文件中。我有非常大的文件。
  • 所以,因为在每个片段之后我都有“TER”而不是“TER1”,所以“TER2”这不起作用。如果我在 pattern1 和 pattern2 中都使用 TER,我只会在输出文件中打印单词 TER。
  • 永远不要使用范围表达式 (/start/,/stop/),因为它们使琐碎的任务比其他方法编写起来非常简单,但随后需要完全重写和/或复制任何更有趣的东西的条件。
【解决方案2】:

写:

我试过这个,但我收到错误“awk:在 源代码行 1":

awk '/TER/{n+=1}{print > "file_"n".txt"}'

这可能是由于输出重定向右侧未加括号的表达式,因为这是每个 POSIX 未定义的行为。如果是这样,那么将"file_"n".txt" 更改为("file_"n".txt") 将使您摆脱困境并进入下一个问题。以下是如何使用任何 awk 真正做你想做的事:

awk '
BEGIN { out = "file" (++c) }
{ print > out }
$0=="TER" {
    close(out)
    out = "file" (++c)
}
' file

【讨论】:

  • 感谢 Ed,我尝试了您的代码(我必须说我不完全理解所有命令的含义,例如 ++c),但我得到的是一个包含所有段的输出文件。如何将两个 TER 之间的每个段放在单独的文件中?但是,也许我做错了什么。我不是很精通awk。
  • 再次 - 根据您在问题中提供的示例,您不是试图在 2 个 TER 之间获取每个段,而是试图获取以 TER 结尾的每个段。如果我发布的脚本不完全符合您的要求,那么您的真实数据与您提供的示例不同。您可能有 DOS 行结尾,因此请尝试在您的文件上运行 dos2unix 或类似内容。或者不太健壮,您可以将$0=="TER" 更改为/TER/
  • 我更新了数据在问题中的显示方式。确实,可能是我没有正确地表达自己。
  • 我发布的解决方案适用于任何仅以 TER 结尾的数据,包括您的原始数据和新数据。wrt ++c 是什么意思 - 在您自己的代码中,您编写了 @987654329 @,您可以在这种情况下改为写++nn++。它只是增加变量n 或在我的情况下为c(用于“计数”)。我为您格式化了您的输入、输出和代码,因此您可以在下一个问题中遵循该示例。有关更多格式信息,请参阅stackoverflow.com/help/formatting
  • 如果我发布的脚本不完全符合您的要求,请告诉我,因为根据您发布的数据,这正是您需要的解决方案,所以如果它不适合您,那么要么你复制/粘贴了我的脚本错误,要么你的真实数据看起来不像你的示例数据(可能只是尾随`rs,正如我之前提到的)。
【解决方案3】:

这可能对你有用(GNU csplit):

csplit -sb '%d' -zf file inputFile '/^TER/+1' '{*}'

这将创建文件 file0filen,每个文件都包含模式 TER 作为每个文件的最后一行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多