根据条件通过一个或多个 grep 命令传递相同的输出
我目前正在编写一个 bash 脚本来修改 LaTeX 编译的输出,以仅包含我在控制台上找到的相关打印内容。因为我希望这个脚本非常彻底,所以我设置了不同的选项来同时切换不同的输出过滤器,具体取决于通过编译给出的信息的性质(致命错误、警告、过度/不足 h/vbox.. .)。
对于那些可能不知道的人来说,我们经常需要连续执行多次编译才能获得完整的 LaTeX 文档,其中包含正确的标签、页码、索引、目录...+其他命令,例如 bibtex
或 makeglossaries
用于参考书目和词汇表。因此,我有一个循环执行所有内容,并在遇到致命错误时停止,但如果只是轻微警告,则应该继续。
我的主命令行通过反向的 grep
管道输出 pdflatex
输出,该反向 grep
查找错误行(以 !
开头)。像这样,只有当 grep
发现致命错误时脚本才会停止。
: | pdflatex --halt-on-error $@ | { ! grep --color=auto '^!.*' -A200; }
但是,当我激活任何其他过滤器(例如,用于过满/欠满行的 '*.full.*'
)时,我需要能够继续编译才能识别它,这是非常有必要的纠正它(嘿,有时,未满的线条并不那么难看......)。
这意味着我的 grep 命令无法像第一行那样反转,并且我无法(或不知道如何)将相同的 grep 与不同的正则表达式一起使用。请注意,如果使用不同的 grep
,它也应该从 pdflatex
输出中读取,并且我无法直接在上面的代码片段之后通过管道传输它。
总而言之,它大致应该是这样的:
pdflatex --> grep for fatal errors --> if more filters, grep for those filters
--> pass to next step
我想出了几种无法正常工作的尝试:
只有当我想使用警告进行编译时,这个才有效。只寻找错误是行不通的。
latex_compilation() {
: | pdflatex --halt-on-error $@ | tee >({ ! grep --color=auto '^!.*' -A200; }) >({ grep --color=auto "$warnings_filter" -A5 };) >/dev/null
}
latex_compilation() {
: | pdflatex --halt-on-error $@ | tee >({ ! grep --color=auto '^!.*' -A200; }) >/dev/null | ({ grep --color=auto "$warnings_filter" -A5 };)
}
或者甚至拼命地
latex_compilation() {
: | pdflatex --halt-on-error $@ |
if [[ "$warnings_on" = true ]]; then
{ grep --color=auto "$warnings_filter" -A5 };
fi
{ ! grep --color=auto '^!.*' -A200; }
}
这个可以工作,但每个步骤使用 2 个编译过程(对于一个大而复杂的文档,您可以轻松地达到 7/8 个编译步骤)。如果可能的话应该避免。
latex_compilation() {
if [[ "$warnings_on" = true ]]; then
: | pdflatex --halt-on-error $@ | \
{ grep --color=auto "$warnings_filter" -A5 };
fi
: | pdflatex --halt-on-error $@ | \
{ ! grep --color=auto '^!.*' -A200; }
}
我花了几个小时在网上寻找解决方案,但还没有找到。 我真的希望这足够清楚,因为总结起来很混乱,而且写起来也很混乱。如果需要清晰起见,您可以在此处找到相关代码。
I am currently writing a bash script to modify the output of my LaTeX compilations to have only what I find relevant printing on the console. As I would like this script to be extremely thorough, I set up different options to toggle different output filters at the same time depending of the nature of the informations given through the compilation (Fatal error, warning, over/underfull h/vbox...).
For those who may not know, we often need to perform several compilations in a row to have a full LaTeX document with correct labels, page numbering, index, table of contents... + other commands like bibtex
or makeglossaries
for bibliography and, well, glossaries. I therefore have a loop that execute everything and stops if there is a fatal error encountered, but should continue if it is only a minor warning.
My main command line is piping the pdflatex
output through a reversed grep
that finds errors line (starting by !
). Like this, the script stops only if grep
found a fatal error.
: | pdflatex --halt-on-error $@ | { ! grep --color=auto '^!.*' -A200; }
But when I activate any other filters (eg. '*.full.*'
for over/underfull lines), I need to be able to continue compiling to be able to identify it there is a major necessity to correct it (hey, sometimes, underfull lines are just not that ugly...).
That means my grep
command cannot be inverted as in the first line, and I cannot (or don't know how to) use the same grep
with a different regex. notice that if if using a different grep
, it should also be read from the pdflatex
output and I cannot pipe it directly following the above snippet.
To sum up, it should roughly look like this :
pdflatex --> grep for fatal errors --> if more filters, grep for those filters
--> pass to next step
I came up with several attempts that did not work properly :
This one works only if I want to compile WITH the warnings. Looking only for errors does not work.
latex_compilation() {
: | pdflatex --halt-on-error $@ | tee >({ ! grep --color=auto '^!.*' -A200; }) >({ grep --color=auto "$warnings_filter" -A5 };) >/dev/null
}
latex_compilation() {
: | pdflatex --halt-on-error $@ | tee >({ ! grep --color=auto '^!.*' -A200; }) >/dev/null | ({ grep --color=auto "$warnings_filter" -A5 };)
}
or even desperately
latex_compilation() {
: | pdflatex --halt-on-error $@ |
if [[ "$warnings_on" = true ]]; then
{ grep --color=auto "$warnings_filter" -A5 };
fi
{ ! grep --color=auto '^!.*' -A200; }
}
This one would work but uses 2 compilation processes for each step (you could easily go up to 7/8 compilations steps for a big and complex document). It should be avoided if possible.
latex_compilation() {
if [[ "$warnings_on" = true ]]; then
: | pdflatex --halt-on-error $@ | \
{ grep --color=auto "$warnings_filter" -A5 };
fi
: | pdflatex --halt-on-error $@ | \
{ ! grep --color=auto '^!.*' -A200; }
}
I spent hours looking for solutions online, but didn't find any yet.
I really hope this is clear enough because it is a mess to sum up, moreover writing it. You can find the relavant code here if needed for clarity.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
,所以我们使用一个。
或者,您可以通过使用您选择的程序语言解析输出来异步执行此操作。对于 Bash,请参阅 https://mywiki.wooledge.org/BashFAQ/001 :
但是 Bash 会速度非常慢。考虑使用 AWK 或 Python 或 Perl。
确切地说,您必须根据您的具体要求自己编写解决方案。
您可以在
>( ... )
内以及基本上任何地方编写整个代码块。管道的退出状态是最右边命令的退出状态(set -o pipelinefail
除外)。将失败的命令放在管道的最右侧。So let's use one.
Or you can do that asynchronously, by parsing the output, in your chosem programmign langauge. For Bash see https://mywiki.wooledge.org/BashFAQ/001 :
But Bash will be extremely slow. Consider using AWK or Python or Perl.
Exactly, you have to write a solution yourself, for your specific requirements.
You can write whole code blocks inside
>( ... )
and basically anywhere. The exit status of a pipeline is the exit status of rightmost command (exceptset -o pipefail
). Put the failing command as the rightmost of the pipeline.建议使用
awk
过滤模式。详细了解
awk
过滤模式 这里。使用
awk
,您可以创建复杂的过滤模式逻辑:!
=not、&&
=and、||
=或。例如,如果您有 3 个过滤正则表达式模式:
Pattern_1
、Pattern_2
、Pattern 3
。示例 1
您可以在以下命令中对所有 3 个模式进行组合过滤:
结果将仅打印与所有 3 个模式匹配的行。
示例 2
您可以在以下命令中对所有 3 个模式进行组合反向过滤:
结果将打印与 3 个模式中任何一个都不匹配的行。
示例 3
您可以创建组合逆过滤器
Pattern_1
并匹配Pattern_2
或Pattern_3
:结果将打印与
Pattern_1< 不匹配的行/code> 但匹配
Pattern_2
或Pattern_3
。Suggesting to use
awk
filtering pattern.Read more about
awk
filtering pattern here.With
awk
you can create complex filtering patterns logic:!
=not,&&
=and,||
=or.For example if you have 3 filtering RegExp patterns:
Pattern_1
,Pattern_2
,Pattern 3
.Example 1
You can make a combined filter all 3 patterns in the following command:
The result will be printing only lines that match all 3 pattern.
Example 2
You can make a combined inverse filter all 3 pattern in the following command:
The result will be printing lines not matching any of the 3 patterns.
Example 3
You can make a combined inverse filter
Pattern_1
and matchPattern_2
orPattern_3
:The result will be printing lines not matching
Pattern_1
but matchPattern_2
orPattern_3
.