我的问题是我需要:
- 查找
regex_pattern
给定根目录中所有文件中匹配的所有行(深度搜索) - 对于匹配的每一行,输出:
- 文件名
- 包含匹配项的行号
- 行内容
- 正则表达式模式
- 将上述数据导入 Excel(因此会想到 CSV 或分隔输出格式)
完成这项任务最简单的方法是什么?
为了证明我对此有所思考,我会编写一个 Perl 脚本,该脚本将单个完全限定的文件名和正则表达式模式作为输入,并使用下面的近似 Perl 处理这些行(我还没有尝试过,但是这个这就是我的第一次尝试):
while (<FILE>) {
$line_number++;
if ($_ =~ m/regex_pattern/) {
# output: file_name\tline_number\tregex_pattern\t$_
# ignore escaping issues for the time being
}
}
我仍然不确定如何通过递归搜索传递每个目录的内容到这个 Perl 脚本中。我可以在 Perl 中进行搜索,但我确信有一种很好的 Unix/Linux 方法可以做到这一点。
我没有和 Perl 结婚。如果有一种方法可以将标准 Unix/Linux 工具链接在一起,那就太棒了。如果没有,我更喜欢使用 Perl,因为我对它的语法有些熟悉。
答案1
像这样的东西吗?
find /search/root -type f -exec awk 'BEGIN{pattern="regex_pattern"} $0 ~ pattern {printf "%s,%s,%s,%s\n",FILENAME,FNR,$0,pattern}' {} +
答案2
start cmd:> find . -type f -name 'search*' -exec awk -v regex=foo \
cont. cmd:> '$0 ~ regex {print FILENAME,FNR,regex,$0 }' {} +
./searchfile1 1 foo a_foo_b
./searchfile2 1 foo foo
答案3
在 Perl 中,利用空文件句柄它对命令行参数进行操作:
#!/usr/bin/perl -n
$, = "\t"; # separator added between arguments to print
while (<>) {
if (/regex_pattern/) {
# $ARGV contains the current file name, $. contains the current line number,
# $_ contains the current line including its terminating newline
print $ARGV, $., 'regex_pattern', $_;
}
$. = 0 if eof; # reset the line number between files
}
要将文件名传递给 Perl 脚本,在 ksh93 或 bash ≥4 或 zsh 中,您可以使用**
图案递归遍历子目录。在 ksh 中,您需要首先使用 启用此模式set -o globstar
。在 bash 中,您需要使用 来启用它shopt -s globstar
。
shopt -s globstar
name_of_perl_script **/*
如果您的 shell 没有**
,或者遇到“命令行太长”错误,您可以使用find
。
find . -type f -exec name_of_perl_script {} +
您还可以通过组合更专业的工具来做到这一点。您可能已经知道 grep 来搜索文件中的模式。该-n
选项使其打印每个匹配行的编号。作为文件名传递/dev/null
是确保grep
也打印文件名的技巧(如果命令行上碰巧有单个文件,则不会执行此操作)。
grep -n 'regex_pattern' **/*
所缺少的只是在必要时更改分隔符(在文件名、行号和行内容之间grep
插入),并在正确的位置插入正则表达式。:
这个简单的替换工作非常适合sed
。请务必正确引用正则表达式。
find . -type f -exec grep -n 'regex_pattern' {} + |
sed 's/^\([^:]*\)\([^:]*\)/\1\t\2\tregex_pattern\t/'