根据条件通过一个或多个 grep 命令传输相同的输出
Piping the same output through one or several grep commands on condition
我目前正在编写一个 bash 脚本来修改我的 LaTeX 编译的输出,使其只包含我在控制台上找到的相关打印内容。因为我希望这个脚本非常彻底,所以我设置了不同的选项来同时切换不同的输出过滤器,具体取决于通过编译给出的信息的性质(致命错误、警告、over/underfull h/vbox...).
对于那些可能不知道的人,我们经常需要连续执行几次编译才能得到一个完整的 LaTeX 文档,其中包含正确的标签、页码、索引、table 的内容... + 其他命令例如 bibtex
或 makeglossaries
用于参考书目和词汇表。因此,我有一个循环执行所有操作并在遇到致命错误时停止,但如果只是轻微警告,应该 继续。
我的主命令行通过反向 grep
管道输出 pdflatex
以查找错误行(从 !
开始)。像这样,脚本仅在 grep
发现致命错误时停止。
: | pdflatex --halt-on-error $@ | { ! grep --color=auto '^!.*' -A200; }
但是当我激活任何其他过滤器时(例如 '*.full.*'
用于 over/underfull 行),我需要能够继续编译才能识别它,因此非常有必要进行更正它(嘿,有时,不足的线条并不 那 丑陋...)。
这意味着我的 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; }
}
我花了几个小时在网上寻找解决方案,但还没有找到。
我真的希望这足够清楚,因为总结起来很乱,而且写起来很乱。如果需要清楚起见,您可以找到相关代码 here。
This one would work but uses 2 compilation processes
所以让我们使用一个。
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。
looking for solutions online
确实如此,您必须自己编写一个解决方案,以满足您的特定要求。
his one works only if I want to compile WITH the warnings. Looking only for errors does not work.
您可以在 >( ... )
中编写整个代码块,基本上可以在任何地方编写。管道的退出状态是最右边命令的退出状态(set -o pipefail
除外)。将失败的命令放在管道的最右边。
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
}
建议使用 awk
过滤模式。
详细了解 awk
过滤模式 here。
使用 awk
您可以创建复杂的过滤模式逻辑:!
=not,&&
=and,||
=or.
例如,如果您有 3 个过滤 RegExp 模式:Pattern_1
、Pattern_2
、Pattern 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_2
或 Pattern_3
:
awk '!/Pattern_1/ && (/Pattern_2/ || /Pattern_3/)' scanned_file1 scanned_file2 ...
结果将打印不匹配 Pattern_1
但匹配 Pattern_2
或 Pattern_3
.
的行
我目前正在编写一个 bash 脚本来修改我的 LaTeX 编译的输出,使其只包含我在控制台上找到的相关打印内容。因为我希望这个脚本非常彻底,所以我设置了不同的选项来同时切换不同的输出过滤器,具体取决于通过编译给出的信息的性质(致命错误、警告、over/underfull h/vbox...).
对于那些可能不知道的人,我们经常需要连续执行几次编译才能得到一个完整的 LaTeX 文档,其中包含正确的标签、页码、索引、table 的内容... + 其他命令例如 bibtex
或 makeglossaries
用于参考书目和词汇表。因此,我有一个循环执行所有操作并在遇到致命错误时停止,但如果只是轻微警告,应该 继续。
我的主命令行通过反向 grep
管道输出 pdflatex
以查找错误行(从 !
开始)。像这样,脚本仅在 grep
发现致命错误时停止。
: | pdflatex --halt-on-error $@ | { ! grep --color=auto '^!.*' -A200; }
但是当我激活任何其他过滤器时(例如 '*.full.*'
用于 over/underfull 行),我需要能够继续编译才能识别它,因此非常有必要进行更正它(嘿,有时,不足的线条并不 那 丑陋...)。
这意味着我的 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; }
}
我花了几个小时在网上寻找解决方案,但还没有找到。 我真的希望这足够清楚,因为总结起来很乱,而且写起来很乱。如果需要清楚起见,您可以找到相关代码 here。
This one would work but uses 2 compilation processes
所以让我们使用一个。
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。
looking for solutions online
确实如此,您必须自己编写一个解决方案,以满足您的特定要求。
his one works only if I want to compile WITH the warnings. Looking only for errors does not work.
您可以在 >( ... )
中编写整个代码块,基本上可以在任何地方编写。管道的退出状态是最右边命令的退出状态(set -o pipefail
除外)。将失败的命令放在管道的最右边。
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
}
建议使用 awk
过滤模式。
详细了解 awk
过滤模式 here。
使用 awk
您可以创建复杂的过滤模式逻辑:!
=not,&&
=and,||
=or.
例如,如果您有 3 个过滤 RegExp 模式:Pattern_1
、Pattern_2
、Pattern 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_2
或 Pattern_3
:
awk '!/Pattern_1/ && (/Pattern_2/ || /Pattern_3/)' scanned_file1 scanned_file2 ...
结果将打印不匹配 Pattern_1
但匹配 Pattern_2
或 Pattern_3
.