寻找一种方法来递归搜索存储库中包含多行字符串的所有文件并返回包含它的文件名。该段落只是一个大约 30 行的标题。所以我知道pcregrep
可以进行多行搜索。但是您需要将整个表达式放入。由于这是我正在搜索的一个很长的段落,因此我想将其放入变量中,然后对该变量执行 grep 操作。所以基本上是这样,find . -name "*.[ch]" | xargs pcregrep -M $paragraph
但这不起作用,任何人都可以指出我正确的方向。
答案1
由于您尝试匹配文件的前 30 行,因此您可以将文本保存在文件中,例如,ref_file
然后用于diff
将参考文件与每个文件中的前 30 行进行比较:
find . -name "*.[ch]" -exec ./myscript {} \; -print
哪里./myscript
#!/bin/sh
head -n 30 "$1" | diff - /path/to/ref_file >/dev/null
所以-print
在第一个命令中,只有在前一个-exec
被评估的情况下才会执行真的,即参考文件与当前文件的前 30 行之间没有差异。
或者,如果您喜欢不使用脚本并将文件名保存在logfile
:
find . -type f -exec sh -c 'head -n 30 "$0" | diff - /path/to/ref_file >/dev/null' {} \; -print >logfile
请注意,这假设您正在寻找完全匹配的内容,否则diff
将以 退出1
,即使差异是一个空格。
答案2
您可以找到要处理的每个文件,find
并将每个文件名提供给专门创建的脚本,以查找匹配项并在匹配时打印文件名;我建议使用脚本而不是单行脚本,以便与提示相比更容易处理多行字符串。
那是:
find . -name "*.[ch]" -exec /path/to/script {} \;
script
这个 Perl 脚本在哪里:
#! /usr/bin/perl
$/ = ""; # sets the input record separator to an empty string
$_ = <>; # stores the content of the file specified in the first argument in $_
$string = <<EOF; # The multi-line string to match starts here
My
multiline
string
EOF
# The multi-line string to match ends here
/\Q$string\E/ && print($ARGV."\n"); # If $_ matches $string, prints the name of the file
$/ = "";
:将Perl的输入记录分隔符设置为空字符串;这具有使 Perl 立即读取脚本第一个参数中指定的整个文件的效果;$_ = <>;
: 将第一个参数指定的文件内容存储在$_
;$string = <<EOF;
[...]EOF
:将[...]的内容存储在$string
(将[...]替换为要匹配的多行字符串);/\Q$string\E/ && print($ARGV."\n");
:如果$_
匹配$string
,则打印文件名。
这是特意制作的测试目录层次结构的示例输出:
% for f in *; do printf '%s:\n\n' "$f"; <<<'' cat "$f" -; done
file1:
My
multiline
string
file2:
My
multiline
string
file3:
My
other
multiline
string
script.pl:
#! /usr/bin/perl
$/ = "";
$_ = <>;
$string = <<EOF;
My
multiline
string
EOF
$string = quotemeta($string);
/$string/&&print($ARGV."\n");
% find . -type f -exec ./script.pl {} \;
./file2
./file1