我如何搜索前面有另一个字符串的某个字符串(在大多数情况下是几行),后面跟着另一个字符串,即包含在某个环境中?
\begin{quote}
%several lines of text
\footnote{%
%probably a few more lines of footnote content
}
%several lines of further text
\end{quote}
因此,我正在搜索\footnote{
引用环境中包含的脚注(以 开头)(以 开头\begin{quote}
,以 结尾end{quote}
,在大多数情况下跨越几行)。实际上,实际上我应该搜索脚注中包含的另一个环境,这些环境发生在引用环境中,从而添加第二层条件,但可能一旦我理解了简化的示例,我就可以弄清楚我的现实世界问题。我搜索的实际环境在包含大约 20 个文件的目录中出现了大约 150 次.tex
,这些文件构成了一本大约 500 页的书的源代码,该书预计将在几天内印刷,并且这种特定的组合会产生不良效果,很多时候,如果不仔细看,就会被忽视。
作为搜索的输出,我想获取匹配发生的文件名(我可能会搜索*tex
,不过,如果这太复杂,我也可以使用 bash for 循环)及其行号。
人们还必须记住这一点
\begin{quote}
%something
\end{quote}
%something
\footnote{%
%something
}
%something
\begin{quote}
%something
\end{quote}
某件事会发生很多次,但这将是误报。
答案1
你不能用 来做到这一点grep
,你需要一些更有能力的东西,比如awk
或perl
。这是在 perl 中执行此操作的一个非常简单的示例:
$ cat find-fn-in-quote.pl
#!/usr/bin/perl
while(<>) {
# strip comments so that we ignore commented-out quotes & footnotes.
s/%[^%].*//;
# detect beginning and end of quotes
if (m/\Qbegin{quote}\E/) { $qt = 1; $ql = $.};
if (m/\Qend{quote}\E/) { $qt = 0 };
if (eof) {
# reset line-counter ($.) after every input file
close(ARGV);
# reset $qt to zero, in case of unbalanced begin/end{quote}
$qt = 0;
};
# skip to next input line if we're not inside a quote.
next unless ($qt);
if (m/\\footnote\{/) {
print "$ARGV: found footnote beginning on line $. inside quote beginning on line $ql\n";
# For terse output, comment out or delete the print statement above
# and un-comment one of these:
#printf "%s:fn=%i:q=%i\n", $ARGV, $., $ql;
#printf "%s:%i:%i\n", $ARGV, $., $ql;
};
};
注意:此脚本无法正确处理嵌套begin{quote}
。我怀疑这会成为一个问题,因为它不太可能在人为的示例之外发生。它还假设引用完全存在于一个文件中 - 事实上,脚本故意强制执行这一点,以确保一个输入文件中的错误(即缺少end{quote}
)不会影响后续文件。
我创建了 3 个文本文件来测试它。 input1.txt
包含您的第一个示例输入。 input2.txt
包含您的第二个示例输入以及您不想匹配的误报。 input3.txt
包含 input2.txt 后跟 input1.txt (即cat input2.txt input1.txt > input3.txt
)。在这些输入文件上运行脚本会产生以下输出:
$ ./find-fn-in-quote.pl *.txt
input1.txt: found footnote beginning on line 3 inside quote beginning on line 1
input3.txt: found footnote beginning on line 14 inside quote beginning on line 12
答案2
awk
的一个版本
awk 'FNR==1{looking=0; print FILENAME}
$0~/begin{quote}/{looking=1;next}
$0~/end{quote}/{looking=0;next}
looking&&$0~/footnote{/{print FNR, $0}' *.tex
只需在报价开始时开始“查看”,在报价结束时停止“查看”。
就像 @cas 示例一样,它会在每次打开文件时重置。
如果您要在脚注中查找另一个环境,那么事情会变得更加棘手,因为您需要开始}
在\footnote
不同的线路上寻找平衡,这是一种不同的动物。
答案3
GNU awk:
awk '
/^\\end{quote}$/ && fire {report = report OFS str}
/^\\end{quote}$/ {block=cont=fire=0; str=""}
/^\\begin{quote}$/ {block=1}
block && /^\\footnote{%$/ {cont=1; str=FNR; next}
block && cont && /}/ {fire=1;cont=0}
ENDFILE {if(report)print FILENAME report; report = ""}
' *.tex
输出格式:
filename line_number line_number ...
每个文件的所有匹配行号都输出在一行中。不匹配的文件名不会显示。