根据条件通过一个或多个 grep 命令传递相同的输出

发布于 2025-01-11 21:05:15 字数 2189 浏览 0 评论 0原文

我目前正在编写一个 bash 脚本来修改 LaTeX 编译的输出,以仅包含我在控制台上找到的相关打印内容。因为我希望这个脚本非常彻底,所以我设置了不同的选项来同时切换不同的输出过滤器,具体取决于通过编译给出的信息的性质(致命错误、警告、过度/不足 h/vbox.. .)。

对于那些可能不知道的人来说,我们经常需要连续执行多次编译才能获得完整的 LaTeX 文档,其中包含正确的标签、页码、索引、目录...+其他命令,例如 bibtexmakeglossaries 用于参考书目和词汇表。因此,我有一个循环执行所有内容,并在遇到致命错误时停止,但如果只是轻微警告,则应该继续。

我的主命令行通过反向的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

匿名的好友 2025-01-18 21:05:15

这个可以工作,但使用 2 个编译过程

,所以我们使用一个。

latex_compilation() {
   local tmp
   tmp=$(pdflatext ... <&-)
   if [[ "$warnings_on" = true ]]; then
       grep --color=auto "$warnings_filter" -A5 <<<"$tmp"
   fi
   ! grep --color=auto '^!.*' -A200 <<<"$tmp"
}

或者,您可以通过使用您选择的程序语言解析输出来异步执行此操作。对于 Bash,请参阅 https://mywiki.wooledge.org/BashFAQ/001

line_is_warning() { .... }
latex_compilation() {
   local outputlines=0 failed
   while IFS= read -r line; do
       if "$warnings_on" && line_is_warning "$line"; do
           outputlines=5  # will output 5 lines after
       fi
       if [[ "$line" =~ ^! ]]; then
           failed=1
           outputlines=200 # will output 200 lines after
       fi
       if ((outputlines != 0)); then
           ((outputlines--))
           printf "%s\n" "$line"
       fi
   done < <(pdflatext ... <&-)
   if ((failed)); then return 1; fi
}

但是 Bash 会速度非常慢。考虑使用 AWK 或 Python 或 Perl。

在线寻找解决方案

确切地说,您必须根据您的具体要求自己编写解决方案。

只有当我想在带有警告的情况下进行编译时,他的方法才有效。仅查找错误是行不通的。

您可以在 >( ... ) 内以及基本上任何地方编写整个代码块。管道的退出状态是最右边命令的退出状态(set -o pipelinefail 除外)。将失败的命令放在管道的最右侧。

latex_compilation() {
    pdflatex --halt-on-error "$@" <&- |
    tee >(
       if "$warnings_on"; then
         grep --color=auto "$warnings_filter" -A5
       else
          cat >/dev/null
       fi
    ) |
    ! grep --color=auto '^!.*' -A200
}

This one would work but uses 2 compilation processes

So let's use one.

latex_compilation() {
   local tmp
   tmp=$(pdflatext ... <&-)
   if [[ "$warnings_on" = true ]]; then
       grep --color=auto "$warnings_filter" -A5 <<<"$tmp"
   fi
   ! grep --color=auto '^!.*' -A200 <<<"$tmp"
}

Or you can do that asynchronously, by parsing the output, in your chosem programmign langauge. For Bash see https://mywiki.wooledge.org/BashFAQ/001 :

line_is_warning() { .... }
latex_compilation() {
   local outputlines=0 failed
   while IFS= read -r line; do
       if "$warnings_on" && line_is_warning "$line"; do
           outputlines=5  # will output 5 lines after
       fi
       if [[ "$line" =~ ^! ]]; then
           failed=1
           outputlines=200 # will output 200 lines after
       fi
       if ((outputlines != 0)); then
           ((outputlines--))
           printf "%s\n" "$line"
       fi
   done < <(pdflatext ... <&-)
   if ((failed)); then return 1; fi
}

But Bash will be extremely slow. Consider using AWK or Python or Perl.

looking for solutions online

Exactly, you have to write a solution yourself, for your specific requirements.

his one works only if I want to compile WITH the warnings. Looking only for errors does not work.

You can write whole code blocks inside >( ... ) and basically anywhere. The exit status of a pipeline is the exit status of rightmost command (except set -o pipefail). Put the failing command as the rightmost of the pipeline.

latex_compilation() {
    pdflatex --halt-on-error "$@" <&- |
    tee >(
       if "$warnings_on"; then
         grep --color=auto "$warnings_filter" -A5
       else
          cat >/dev/null
       fi
    ) |
    ! grep --color=auto '^!.*' -A200
}
留蓝 2025-01-18 21:05:15

建议使用 awk 过滤模式。

详细了解 awk 过滤模式 这里

使用awk,您可以创建复杂的过滤模式逻辑:!=not、&&=and、||=或。

例如,如果您有 3 个过滤正则表达式模式:Pattern_1Pattern_2Pattern 3

示例 1

您可以在以下命令中对所有 3 个模式进行组合过滤:

awk '/Pattern_1/ && /Pattern_2/ && /Pattern_3/ 1' scanned_file1 scanned_file2 ...

结果将仅打印与所有 3 个模式匹配的行。

示例 2

您可以在以下命令中对所有 3 个模式进行组合反向过滤:

awk '!/Pattern_1/ && !/Pattern_2/ && !/Pattern_3/ 1' scanned_file1 scanned_file2 ...

结果将打印与 3 个模式中任何一个都不匹配的行。

示例 3

您可以创建组合逆过滤器 Pattern_1 并匹配 Pattern_2Pattern_3

awk '!/Pattern_1/ && (/Pattern_2/ || /Pattern_3/)' scanned_file1 scanned_file2 ...

结果将打印与 Pattern_1< 不匹配的行/code> 但匹配 Pattern_2Pattern_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:

awk '/Pattern_1/ && /Pattern_2/ && /Pattern_3/ 1' scanned_file1 scanned_file2 ...

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:

awk '!/Pattern_1/ && !/Pattern_2/ && !/Pattern_3/ 1' scanned_file1 scanned_file2 ...

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 match Pattern_2 or Pattern_3:

awk '!/Pattern_1/ && (/Pattern_2/ || /Pattern_3/)' scanned_file1 scanned_file2 ...

The result will be printing lines not matching Pattern_1 but match Pattern_2 or Pattern_3.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文