【问题标题】:Bash getting lines between a line number and a patternBash 在行号和模式之间获取线
【发布时间】:2016-01-08 19:03:18
【问题描述】:

我有一个函数应该获取特定行号之间的行,将其传递给它并存储在一个变量中,以及模式为“endhelp”的下一行

我现在的代码:

START_LINE=$1 #-- On which line the help is and where the search should start

#-- Where the help command block ends
END_LINE[1]=$(sed -n "$START_LINE,/endhelp/p=" filename)

#-- Add one number to END_LINE as a second array value to speed line extracting
END_LINE[2]=$((${END_LINE[1]}+1))

#-- The actual line extraction that outputs the whole lines
sed -n "$START_LINE,${END_LINE[1]}p; ${END_LINE[2]}q" filename

所以如果我有这样的东西:(注意:输入文件中还有其他类似的块,所以这就是起始行很重要的原因)

-- some text --

help 
    text and some more text
    more words and text
    third help thing line
    stuff
    hi
endhelp

-- some other text --

输出将是:

text and some more text
more words and text
third help thing line
stuff
hi

上面的代码可以工作吗?可以更有效地完成吗?还有当它检测到只有字符串'endhelp'的空行时如何让它停止?

更新

下面是更新后的代码,可以满足我的要求:

START_LINE=$2 #-- Where the help command block starts
awk 'BEGIN {OUTPUT=0} NR=='$START_LINE' {OUTPUT=1} /^endhelp$/ {exit} OUTPUT'

如果only 行有字符串'endhelp',它会停止并从$START_LINE 开始打印。我添加了BEGIN {OUTPUT=0},否则它会在某些旧设备上出错。

更新2

我再次编辑了代码,以修复它在到达“START_LINE”之前在空行上看到“endhelp”时退出的问题:

awk 'NR>='$START_LINE' {if ($0 ~ /^endhelp$/) {exit} else {$1=$1; print}}'

它更小,速度更快。它还添加了$1=$1,它从当前行中删除了尾随和前导空格。如果不需要,可以将其安全移除。

【问题讨论】:

  • 你传递给脚本的是哪一行?
  • “帮助”所在的行,所以它会从那里开始打印

标签: regex linux bash awk sed


【解决方案1】:

可以更有效地完成吗?还有当它检测到只有字符串'endhelp'的空行时如何让它停止?

这是一个比你的脚本更高效的 awk 版本:

awk -v n=$1 '/^endhelp$/{exit} p; NR==n || /^help$/{p=1}' file

这将从给定的行号开始打印,或者当一行中只有help 文本时开始打印。它将继续打印,直到出现带有endhelp 文本的行。那时awk 将只是exit 并且不会处理文件的其余部分。

【讨论】:

  • 谢谢!我在此基础上编辑了我的代码,效果非常好!
【解决方案2】:

如果您已经在搜索起始行,为什么不在这些锚点之间打印?

以 Perl 为例:

$ echo "$help_text" 
help 1
    text 1 and some more text
    more words and text
    third help thing line
    stuff
    hi
endhelp

help 2
    text 2 and some more text
    more words and text
    third help thing line
    stuff
    hi
endhelp

help 3
    text 3 and some more text
    more words and text
    third help thing line
    stuff
    hi
endhelp

您可以像这样打印锚点 help \dendhelp 之间的文本:

$ echo "$help_text" | perl -0777 -ne 'print $1 if /^help[ \t]+3(.*?)^endhelp/ms'

    text 3 and some more text
    more words and text
    third help thing line
    stuff
    hi

在 awk 中:

$ echo "$help_text" | awk '
> /^help 3/ {flag=1; next}
> /^endhelp/ {flag=0}
> flag {print}'
    text 3 and some more text
    more words and text
    third help thing line
    stuff
    hi

如果您设置使用行号作为块的开头,您可以这样做:

$ echo "$help_text" | awk '
NR==17 {flag=1; next}
/^endhelp/ {flag=0}
flag {print}'
    text 3 and some more text
    more words and text
    third help thing line
    stuff
    hi

【讨论】:

  • 其他情况下它可以工作,但是如果该行以“endhelp”开头,它会中断,如果该行只有字符串“endhelp”,我希望它停止。但感谢您引导我走向正确的方向。
【解决方案3】:

我宁愿使用awk oneliner 来提取你需要的行:

awk "NR==$1 && /help/ {flag=1;next}/endhelp/{flag=0}flag" filename

输入文件名和 NR==3:

-- some text --

help 
    text and some more text
    more words and text
    third help thing line
    stuff
    hi
endhelp

-- some other text --

输出:

text and some more text
more words and text
third help thing line
stuff
hi

你也可以这样做,只需指定行号:

awk "NR==$1 {flag=1;next}/endhelp/{flag=0}flag" filename

【讨论】:

  • 我考虑过使用 awk,否则这很好,但是应该将剪切应该开始的行提供给函数。输入文件中可以有多个help text more text endhelp 段,因此简单地让它从第一个help 开始到endhelp 是行不通的。我会将此添加到问题中以供将来回答。
  • 可以指定行号开始
  • 拥有awk '$'$START_LINE',{flag=1;next}/endhelp/{flag=0}flag' filename?
  • 很抱歉,如果行中的任何位置有“endhelp”,这将停止打印行。仅当该行为空时才应停止,但感谢您为我指出正确的方向。
猜你喜欢
  • 1970-01-01
  • 2017-02-18
  • 1970-01-01
  • 1970-01-01
  • 2018-06-08
  • 2014-03-13
  • 2018-07-16
  • 2013-05-28
  • 1970-01-01
相关资源
最近更新 更多