Bash在行号和模式之间获取行

时间:2016-01-08 19:03:19

标签: regex linux bash awk sed

我有一个函数,它应该在特定行号之间获取行,传递给它并存储在变量中,以及带有'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'

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

UPDATE2

我再次编辑了代码,如果在“START_LINE”之前在其他空行上看到“endhelp”,则将其修复退出:

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

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

3 个答案:

答案 0 :(得分:2)

  

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

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

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

这将从给定的行号开始打印,或者当行中只有help文本时打印。它将继续打印,直到显示endhelp文本的行。此时awk只会exit,文件的其余部分将不会被处理。

答案 1 :(得分:1)

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

以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

答案 2 :(得分:0)

我宁愿使用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