Bash 如何使用命令行在多个文件中搜索一段代码并计算其发生次数?

Bash 如何使用命令行在多个文件中搜索一段代码并计算其发生次数?,bash,awk,sed,grep,Bash,Awk,Sed,Grep,我有一个包含多个子目录和文件的项目目录。其中一些文件重复相同的代码块(多次定义的函数)。有时,很多时候这些函数共享相同的名称,但有不同的定义 我的目标之一是找到所有使用相同名称定义函数的实例。我可以通过我的文本编辑器grep和ripgrep来实现这一点,只搜索声明函数的行,比如def set\u name 在获得这些实例之后,我的第二个目标是比较它们的方法定义,以便稍后确定如何处理使用相同名称声明但包含与它们应有的代码块不同的代码块的函数 我想我需要做的是搜索整个代码块,但我不知道如何搜索多行文

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

我的目标之一是找到所有使用相同名称定义函数的实例。我可以通过我的文本编辑器grep和ripgrep来实现这一点,只搜索声明函数的行,比如
def set\u name

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

我想我需要做的是搜索整个代码块,但我不知道如何搜索多行文件,因为我的文本编辑器和grep都不允许这样做,而且ripgrep还没有发布多行功能

我知道的是函数的名称以及函数的外观。我需要找到的是,在哪些地方,其他函数被声明为具有相同的名称,但它们是不同的。我需要找到这些函数是什么,以及有多少次出现(将有许多次重复)

假设我要搜索的函数名为
Say_hi
,它应该如下所示:

def say_hi(name)
  return "Hi, #{name}!"
end
我想找到项目文件夹中的所有函数,这些函数基本上是从<代码> DEF SayyHi(name)< /C>开始的,并以<代码>结束<代码>结束,但不包含恰好<代码>返回“Hi,{{Name }!”/<代码>中间的代码块。

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

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

在大多数情况下,这是可行的,我得到的结果是第1行是相同的,第2行是其他的。我想知道如何计算这些事件,以便以后帮助我找到所有的变化。这是一个很好的方法,还是我想得太多了?

如果你的函数总是像你展示的那样简单,例如:

$ 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脚本中执行与此等效的操作,但这种方法将识别/规范化函数与您希望对它们执行的操作分离开来)


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

如果您的功能始终像您所展示的那样简单,例如:

$ 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脚本中执行与此等效的操作,但这种方法将识别/规范化函数与您希望对它们执行的操作分离开来)



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

尝试使用
wc-l
。它会告诉你计数。我想你至少需要一个基本的解析器,忽略注释和空白的差异。我觉得如果你只找到函数的每一次出现,给它一些随机输入,然后比较输出,会更容易。如果多个不同输入的函数之间的输出相同,您可以合理地假设它们是相同的。@pkqxdd编写一个工具来计算(并处理)作为参数传递给每个函数的值的类型以及输出类型和返回代码的类型,将是非常困难的,两个输出相同内容的函数并不意味着它们是相同的函数(例如,考虑
if(x>1)print“ERR”
vs
if(x>2)print“ERR”
传递了arg
x=3
)。在尝试使用
wc-l
时,会询问并回答查找代码块并替换它。它会告诉你计数。我想你至少需要一个基本的解析器,忽略注释和空白的差异。我觉得如果你只找到函数的每一次出现,给它一些随机输入,然后比较输出,会更容易。如果多个不同输入的函数之间的输出相同,您可以合理地假设它们是相同的。@pkqxdd编写一个工具来计算(并处理)作为参数传递给每个函数的值的类型以及输出类型和返回代码的类型,将是非常困难的,两个输出相同内容的函数并不意味着它们是相同的函数(例如,考虑
if(x>1)print“ERR”
vs
if(x>2)print“ERR”
传递了arg
x=3
)。找到一个代码块并替换它会在感谢您的回复中被询问和回答。我可以在整个文件目录而不是单个文件上执行此操作吗?当然可以。为什么不试试呢?我再次向你致敬,这是一种巧妙的方法@EdMorton,不幸的是,这对我来说不起作用,因为我需要在文件中添加正常的空白。如果我创建简单的文件,比如