我编写了一个 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"
}