如何在标记(*)之间选择除最后一个之外的多行(使用sed)?我该如何选择其余所有内容?

时间:2016-03-17 21:09:20

标签: regex linux bash sed

我有一个巨大的.txt文件格式如下(每个非空白行以三个空格开头):

   unwanted text
   unwanted text

   *wanted text
   abc
   def

   *wanted text 2
   content
   content

   *wanted text 3
   content
   content

   (...)

我正在寻找一个代码,它只返回第一个“*”发生的行,直到(但不包括)第二个“*”发生。

浏览多个StackOverflow帖子,我已经设法使用Ubuntu(GNU / Linux)获得以下工作代码:

sed -n -e '/^   \*/{p;q}' bigfile.txt && sed -e '1,/   \*/d' -e '/   \*/,$d' bigfile.txt

它给了我以下(按需)输出:

*wanted text
abc
def
\n (representing a wanted blank line)

虽然这正是我想要的输出,你必须同意我,这是一个有点愚蠢的代码,因为我必须使用sed两次。首先,我只有它的第二部分(在“&&”之后)并且除了第一行(*想要的文本)之外将返回正确的东西。然后我附加了第一部分代码(在“&&”之前),所以我也得到了想要部分的第一行。我试过的每一段代码都没有给我带来更好的结果。

这是永远不够的,它是一个非常大的文件,我将在脚本中递归地执行此操作,因此,如果可能的话,a / q(在找到第一个结果后退出)是可取的。

完成此操作后,我需要将最后一个命令的结果作为输入,因此我可以获得完整的文本,除了先前的结果,如下:

   unwanted text
   unwanted text

   *wanted text 2
   content
   content

   *wanted text 3
   content
   content

   (...)

总而言之,我的两个问题是:

  • 有没有办法像上面描述的那样使用sed one-liner获得第一个所需的输出,而不需要调用sed两次(最好在找到摘录后退出所以它不会搜索所有大文件)?我很确定这是一个更优雅的解决方案。
  • 我怎样才能得到'除了先前问题的结果之外的整个文本'(如'反向'输出?)? 我没有软件必需品,我只是需要它,所以我可以运行先前的 一次又一次地动作和“不断更新”输入并处理每个 根据具体情况输出第一个命令。

希望我足够清楚。请问我是否缺少任何细节。 非常感谢你的关注!

1 个答案:

答案 0 :(得分:0)

awk救援!

$ awk '$1~/^*/{if(f) exit; f=1} f' file

   *wanted text
   abc
   def
   <-- here is the empty line formatter eats

第二部分

$ awk '$1~/^*/{f++} !f||f>1' file

   unwanted text
   unwanted text

   *wanted text 2
   content
   content

   *wanted text 3
   content
   content

   (...)