过滤文件匹配模式的行,仅打印其中的一部分

时间:2018-01-15 11:06:36

标签: regex bash sed

我有个人文件,我声明这样的函数:

function funcname {
    # ...
}

我想要一个输出文件中每个funcname的命令,如下所示:

funcname1
funcname2
...

我不明白为什么这个命令不起作用:

cat filename | sed -ne '/^function.*{$/p' -e 's/function \([0-9a-zA-Z_]+\) {/(\1)/'

虽然这个(它给出了一个当前活动的分支):

git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /'

现在我可以用它代替:

cat filename | grep '^function' | cut -d' ' -f 2

但我真的很想了解上面命令(第一个)的错误。

1 个答案:

答案 0 :(得分:2)

已编辑以合并this评论中提及的案例。

Bash函数定义可以使用我们没有function关键字来编写,如下所示

# cat 48261735 
function testfun1
{
echo "testfun1"
}
testfun2()
{
echo "testfun2"
}
function testfun3{
echo "testfun3"
}

获取所有功能名称的脚本

# sed -nE -- '/function/s/^.*function[[:blank:]]*([^[:blank:]{}]*).*$/\1/p;/\(\)/s/^[[:blank:]]*([^(]*).*$/\1/p' 48261735
testfun1
testfun2
testfun3

现在,您的脚本出了什么问题。

首先,你做了useless use of cat。可以使用--将文件直接输入脚本,以通知sed我们已完成参数。 --是针对角落案例的解决方法,您的文件名以-开头。以下是一个例子

sed 'your parameters and script here' -- filename

然后,你的第一个表达

-e '/^function.*{$/p'

id不合适。你真的希望在实际进行替换之前打印东西吗?相反,您可以在s命令之后添加一个p标志,告诉sed替换的结果应该打印到stdout

现在,来到替换部分,您不会计算函数关键字和函数名称之前和之后的多个空格。

更重要的是 ,因为您没有使用扩展正则表达式,所以您在选择部分+之前缺少转义字符。所以你可以想出像

这样的东西
sed -ne '/^[[:blank:]]*function.*/s/^[[:blank:]]*function[[:blank:]]*\([0-9a-zA-Z_]\+\)[[:blank:]]*{*/\1/p' -- filename
testfun1
testfun3

请注意覆盖p选项的s命令后面的-n标志。 Evenn那么你的脚本会错过testfun2,因为它没有考虑functon_name()格式。

我建议你使用sed的扩展正则表达式选项,即-E,它可以帮助你避免很多转义序列。

希望事情很清楚。 : - )