用于构建 sed 模式的变量

用于构建 sed 模式的变量

我编写了一个 bash 函数来打印文件中匹配## mode: org和 的行之间的文本部分## # End of org,各部分之间有一个空行。 在 之前##可以有任意数量的空格。

这是要从中提取信息的文件的示例。

file: test.sh

## mode: org
## * Using case statement
## # End of org
case $arg in
 ("V")
   echo "Author"
   ;;
 (*)
   ## mode: org
   ## ** Silent Error Reporting Mode (SERM) in getopts
   ## *** Detects warnings without printing built-in messages.
   ## *** Enabled by colon {:} as first character in shortopts.
   ## # End of org
   break
   ;;
esac

期望的输出是

代码:

* Using case statement

** Silent Error Reporting Mode (SERM) in getopts
*** Detects warnings without printing built-in messages.
*** Enabled by colon {:} as first character in shortopts.

这是我正在使用的功能

capture-org ()
{
  local efile="$1"

  local begsec="## mode: org"
  local endsec="## # End of org"

  sed -n "/^[[:space:]]*${begsec}$/,/^[[:space:]]*${endsec}$/s/ *//p'" "$efile" |
   sed 's/^'"${begsec}"'$/\n'"${begsec}"'/' |
   sed '/^'"${begsec}"'$/d' | sed '/^'"${endsec}"'$/d' | cut -c 3-
}

我想简化函数,使用变量来构造模式。但需要一些帮助来编译命令,这样我就不必调用sed那么多次。

也许使用awk会是一个更好的策略。

capture-org ()
{
  local efile="$1"

  local begsec='^[[:space:]]*## mode: org$'
  local endsec='^[[:space:]]*## # End of org$'

  sed -n "/${begsec}/,/${endsec}/s/ *//p" "$efile" |
   sed 's/^## # End of org$/## # End of org\n/' |
   sed '/^## mode: org$/d' | sed '/^## # End of org$/d' | cut -c 3-
}

答案1

我确实会使用一些更复杂的东西来实现这一点。比如 awk:

$ awk -v start="$begsec" -v end="$endsec" \
    '{ 
        if($0~start){want=1; next} 
        if($0~end){want=0; print ""; next} 
        gsub(/\s*#+\s*/,""); 
     } want' file
* Using case statement

** Silent Error Reporting Mode (SERM) in getopts
*** Detects warnings without printing built-in messages.
*** Enabled by colon {:} as first character in shortopts.

或者,使用最后一个函数作为模板:

capture-rec ()
{

  local begsec='## mode: org'
  local endsec='## # End of org'

  awk -v start="$begsec" -v end="$endsec" \
    '{ 
        if($0~start){want=1; next} 
        if($0~end){want=0; print ""; next} 
        gsub(/\s*#+\s*/,""); 
     } want' "$1"
}

一个可能很重要的警告是,这并不要求和是行上除前导空格之外的唯一$begsec内容$endsec,就像您的方法一样,它只是在行上的任何地方搜索它们。考虑到您要查找的内容,我假设这不是什么大问题,但如果是,您可以使用这个,它将在匹配之前删除行首和行末的空格:

capture-rec ()
{

  local begsec='## mode: org'
  local endsec='## # End of org'

    awk -v start="$begsec" -v end="$endsec" \
    '{ 
        sub(/^[[:space:]]*/,"");
        sub(/[[:space:]]*$/,"");
        if($0==start){ want=1; next} 
        if($0==end){   want=0; print ""; next} 
        gsub(/\s*#+\s*/,""); 
     } want' "$1"
}

相关内容