首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >查找内容与搜索字符串匹配的函数。

查找内容与搜索字符串匹配的函数。
EN

Unix & Linux用户
提问于 2021-10-05 14:15:20
回答 2查看 414关注 0票数 4

我希望在bash中搜索所有已定义的函数,以查找某些搜索字符串。下面是一个开始,但我想在下一行中删除所有没有空格的术语(即删除在函数正文中没有找到$1的所有条目)。

代码语言:javascript
复制
fu() { declare -f | grep -e \(\) -e $1; }

例如,这一产出:

代码语言:javascript
复制
...
tt ()
untargz ()
urlfix ()
ver ()
    [ -f /etc/lsb-release ] && RELEASE="$(cat /etc/lsb-release | grep DESCRIPTION | sed 's/^.*=//g' | sed 's/\"//g') ";
vi. ()
vi.su ()
...

会减少到

代码语言:javascript
复制
...
ver ()
    [ -f /etc/lsb-release ] && RELEASE="$(cat /etc/lsb-release | grep DESCRIPTION | sed 's/^.*=//g' | sed 's/\"//g') ";
...

一个甚至更好的方法(如果可能的话)将是,如果每个匹配的功能可以确定和充分显示。

我的设想大致是:

  • 收集包含搜索字符串的函数的名称(函数的名称在匹配之前总是行上的一个单词,从^开始,然后是以()$结尾的行),然后对每个名称使用command -V,OR,再次执行declare -f,但这次,使用这些名称并匹配从{} ( {}^上都是单行)的所有内容--我知道grep/awk/sed可以对那些有这种知识的人做令人惊奇的事情。

最终结果将是运行fu awk,它将显示函数正文中包含awk的每个函数的定义。

EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2021-10-05 14:38:45

想到管道接收端的以下awk命令:

代码语言:javascript
复制
declare -f | awk -v srch="pattern" 'NF==2 && $2=="()"{if (m) print buf; buf=""; m=0}
                                    buf && index($0,srch){m=1}
                                    {buf=buf ORS $0}
                                    END{if (m) print buf}'

其思想是在解析buf的输出时将每个函数的声明和正文存储在缓冲区declare -f中,但只有在找到搜索字符串时才打印缓冲区。

  • 如果程序遇到一个只包含两个字段(=空格分隔的“word”)的行,则该程序将识别新函数定义的开始,其中第二个字段是()。如果在解析前一个函数(由标志m为1指示)时找到匹配,则将打印缓冲区buf。缓冲区和标志都将被重置。
  • 搜索词以awk变量srch的形式传递给程序。如果在当前行中找到它( index函数返回一个非零的结果),则m标志设置为1,但只有当我们不在函数声明开始的行(由buf不为空表示)时,否则函数名称中的匹配也将计算在内。
  • 每一行都将被附加到缓冲区buf,并由输出记录分隔符ORS (默认为换行符)与以前的内容分隔开来。
  • 最后,如果找到匹配,则执行另一次检查,如果是,则打印缓冲区。如果没有检查,就永远不会考虑最后一个函数定义。

该程序通过使用index()awk函数执行全字符串搜索.如果希望搜索基于正则表达式匹配,则需要将条件更改为

代码语言:javascript
复制
index($0,srch)

代码语言:javascript
复制
$0~srch

(但是,与往常一样,要注意的是,搜索包含对正则表达式具有特殊意义的字符的字符串会变得更麻烦)。

票数 5
EN

Unix & Linux用户

发布于 2021-10-05 15:30:26

对于那些在zsh中做同样事情的人来说,要获得其身体与模式匹配的函数的函数定义,您可以这样做:

代码语言:javascript
复制
typeset -f '' ${(k)functions[(R)pattern]}

用于覆盖没有匹配函数的情况的。或者一种更干净的方式:

代码语言:javascript
复制
() { (($#)) && typeset -f -- "$@"; } ${(k)functions[(R)pattern]}

bash中,您可以使用以下方法执行类似的操作:

代码语言:javascript
复制
compgen -A function | (
  ret=1
  while IFS= read -r fn; do
    def=$(typeset -f -- "$fn") &&
      [[ ${def#*'()'} = pattern ]] &&
      printf '%s\n' "$def" &&
      ret=0
  done
  exit "$ret"
)

虽然这样做效率很低,因为函数名列表一次只读取一个字节(因为read的S输入是一个管道),而且每个函数都要分叉一个进程。

代码语言:javascript
复制
compgen -A function | (
  readarray -t functions
  for fn in "${functions[@]}"; do
    typeset -f -- "$fn" && printf '\0'
  done
) | (
  ret=1
  readarray -td '' fn_definitions
  for def in "${fn_definitions[@]}"; do
    [[ ${def#*'()'} = pattern ]] &&
      printf '%s\n' "$def" &&
      ret=0
  done
  exit "$ret"
)

readarray相反,read不需要每次读取一个字节的输入,因为它无论如何都会消耗所有的输入。我们用NUL字符分隔函数定义,因为无论如何,bash (与zsh相反)不能将该字符存储在函数定义/名称或变量内容中,然后可以使用readarray -td '' (这需要bash-4.4+)将其分解为数组。

这避免了依赖启发式方法,例如()的存在(很可能也会出现在函数的主体中)来猜测typeset -f输出中每个函数定义从哪里开始的。

票数 4
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/671949

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档