首页 > 解决方案 > 如何使用命令行在多个文件中搜索代码块并计算其出现次数?

问题描述

我有一个包含多个子目录和文件的项目目录。其中一些文件重复相同的代码块(多次定义的函数)。有时很多时候这些函数共享相同的名称但有不同的定义。

我的目标之一是找到所有定义了同名函数的实例。我可以通过仅搜索声明函数的行(例如def set_name.

在获得这些实例之后,我的第二个目标是比较它们的方法定义,以便我以后可以确定如何处理使用相同名称声明但包含与它们应该具有的不同代码块的函数。

我认为我需要做的是搜索整个代码块,但我不知道如何在文件中搜索多行,因为我的文本编辑器和 grep 都不允许这样做 - 并且 ripgrep 尚未发布该--multiline功能。

我所知道的是函数的名称以及函数的外观。我需要找到的是其他函数被声明为同名但不同的地方。我需要找出这些函数是什么,以及出现了多少次(会有很多重复)。

假设调用了我要搜索的函数say_hi,它应该如下所示:

def say_hi(name)
  return "Hi, #{name}!"
end

我想在项目文件夹中找到基本上以开头def say_hi(name)和结尾end但不完全包含return "Hi, #{name}!"中间代码块的所有函数。

我一直在使用 grep 来查找代码块的前两行,其中声明了同名的函数,但第二行不是应该的:

grep 'def say_hi(name)' -A 2 -nr directory | grep -v 'return "Hi #{name}!"'

在大多数情况下,这是可行的,并且我遇到了第 1 行相同而第 2 行是其他内容的情况。我想知道如何计算这些出现的次数,以便以后帮助我找到所有的变化。这甚至是一个好方法还是我想多了?

标签: bashawksedgrep

解决方案


如果您的功能总是像您展示的那样简单,例如:

$ cat file
def foo(name)
  return "Hi, #{name}!"
end

def bar(name)
  return "Hi, #{name}!"
end

然后你可以做这样的事情来规范空白并将每个函数打印为一行:

$ cat tst.awk
/^def / { fn=""; inFn=1 }
inFn    { fn=(fn == "" ? "" : fn ORS) $0 }
/^end$/ { prt(); inFn=0 }

function prt() {
    gsub(/[[:space:]]+/," ",fn)
    print fn
}

$ awk -f tst.awk file
def foo(name) return "Hi, #{name}!" end
def bar(name) return "Hi, #{name}!" end

然后在文件之间运行一个普通的旧差异或

$ awk -f tst.awk file | sort | uniq -c
      1 def bar(name) return "Hi, #{name}!" end
      1 def foo(name) return "Hi, #{name}!" end

$ awk -f tst.awk file | grep '^def foo *(' | sort | uniq -c
      1 def foo(name) return "Hi, #{name}!" end

或类似的方法来查找所有或单个函数的单次/多次出现(是的,您也可以在一个 awk 脚本中执行与此等效的操作,但这种方法将识别/规范化函数与您想要对它们执行的操作分开)。

显然这不是一个解析器,所以如果你需要删除注释,例如,那么你必须弄清楚如何将注释与字符串中的类似文本分开,等等。它会压缩/更改字符串中的空白,就像它将在令牌之间,因此它不(也不能)精确,但它可能足以满足您的需求。


推荐阅读