=encoding utf-8

=head1 NAME

App::Greple::tee - 用外部命令结果替换匹配文本的模块

=head1 SYNOPSIS

    greple -Mtee command -- ...

=head1 VERSION

Version 0.9903

=head1 DESCRIPTION

Greple的B<-Mtee>模块将匹配的文本部分发送到给定的过滤命令，并以命令结果替换它们。这个想法来自于名为B<teip>的命令。它就像绕过部分数据到外部过滤命令。

过滤命令在模块声明之后（C<-Mtee>），以两个破折号结束（C<-->）。例如，下一个命令调用C<tr>命令，参数为C<a-z A-Z>，用于数据中的匹配字。

    greple -Mtee tr a-z A-Z -- '\w+' ...

上述命令将所有匹配的单词从小写转换为大写。事实上，这个例子本身并不那么有用，因为B<greple>可以用B<--cm>选项更有效地做同样的事情。

默认情况下，命令作为单个进程执行，所有匹配的数据会混合发送到该进程。如果匹配的文本不是以换行结束，则会在发送前添加，并在接收后删除。输入和输出数据是逐行映射的，因此输入和输出的行数必须相同。

使用 B<--discrete> 选项时，每个匹配的文本区域都会调用单独的命令。你可以通过以下命令来区分。

    greple -Mtee cat -n -- copyright LICENSE
    greple -Mtee cat -n -- copyright LICENSE --discrete

使用B<--discrete>选项时，输入和输出数据的行数不一定相同。

=head1 OPTIONS

=over 7

=item B<--discrete>

为每个匹配的零件单独调用新的命令。

=item B<--bulkmode>

使用 <--discrete> 选项时，每条命令都会按需执行。回车符
<--bulkmode> option causes all conversions to be performed at once.

=item B<--crmode>

该选项将每个程序块中间的换行符替换为回车符。执行命令的结果中包含的回车符将还原为换行符。因此，可以批量处理由多行组成的数据块，而无需使用 B<--discrete>选项。

=item B<--fillup>

将一连串非空行合并为一行，然后再传递给过滤命令。宽窄字符之间的换行符会被删除，其他换行符会被空格替换。

=item B<--blocks>

通常，与指定搜索模式匹配的区域将被发送到外部命令。如果指定了该选项，将处理的不是匹配区域，而是包含该区域的整个块。

例如，要将包含C<foo>模式的行发送到外部命令，需要指定与整行匹配的模式：

    greple -Mtee cat -n -- '^.*foo.*\n' --all

但如果使用 B<-blocks> 选项，就可以简单地完成如下操作：

    greple -Mtee cat -n -- foo --blocks

使用 B<-blocks> 选项时，该模块的行为更类似于 L<teip(1)> 的 B<-g> 选项。否则，其行为类似于带有 B<-o> 选项的 L<teip(1)>。

不要将 B<--blocks> 与 B<--all> 选项一起使用，因为块将是整个数据。

=item B<--squeeze>

将两个或多个连续换行符合并为一个。

=back

=head1 WHY DO NOT USE TEIP

首先，只要你能用B<teip>命令做，就使用它。它是一个优秀的工具，比B<greple>快得多。

因为B<greple>是为处理文档文件而设计的，它有许多适合于它的功能，如匹配区控制。也许值得使用B<greple>来利用这些功能。

另外，B<teip>不能将多行数据作为一个单元来处理，而B<greple>可以在由多行组成的数据块上执行单个命令。

=head1 EXAMPLE

下一个命令将找到包含在Perl模块文件中的L<perlpod(1)>风格文件内的文本块。

    greple --inside '^=(?s:.*?)(^=cut|\z)' --re '^(\w.+\n)+' tee.pm

你可以通过DeepL，通过执行上述命令与B<-Mtee>模块相结合，调用B<deepl>命令，像这样翻译它们。

    greple -Mtee deepl text --to JA - -- --fillup ...

不过，专用模块L<App::Greple::xlate::deepl>对这个目的更有效。事实上，B<tee>模块的实现提示来自B<xlate>模块。

=head1 EXAMPLE 2

接下来的命令会发现LICENSE文件中有一些缩进的部分。

    greple --re '^[ ]{2}[a-z][)] .+\n([ ]{5}.+\n)*' -C LICENSE

      a) distribute a Standard Version of the executables and library files,
         together with instructions (in the manual page or equivalent) on where to
         get the Standard Version.

      b) accompany the distribution with the machine-readable source of the Package
         with your modifications.

你可以通过使用B<tee>模块和B<ansifold>命令来重新格式化这部分内容。

    greple -Mtee ansifold -rsw40 --prefix '     ' -- --discrete --re ...

      a) distribute a Standard Version of
         the executables and library files,
         together with instructions (in the
         manual page or equivalent) on where
         to get the Standard Version.

      b) accompany the distribution with the
         machine-readable source of the
         Package with your modifications.

离散选项会启动多个进程，因此进程的执行时间会更长。因此，你可以使用 C<--separate '\r'>选项和 C<ansifold>，后者会使用 CR 字符而不是 NL 字符生成单行。

    greple -Mtee ansifold -rsw40 --prefix '     ' --separate '\r' --

然后通过L<tr(1)>命令或其他命令将CR字符转换成NL。

    ... | tr '\r' '\n'

=head1 EXAMPLE 3

考虑一下要从非标题行中搜索字符串的情况。例如，你可能想搜索 C<docker image ls> 命令中的 Docker 镜像名称，但要保留标题行。你可以通过以下命令来实现。

    greple -Mtee grep perl -- -Mline -L 2: --discrete --all

选项 C<-Mline -L 2:> 会检索倒数第二行，并将其发送给 C<grep perl> 命令。需要使用选项 --discrete 是因为输入和输出的行数会发生变化，但由于命令只执行一次，因此不会影响性能。

如果尝试用 B<teip> 命令做同样的事情，C<teip -l 2- -- grep> 会出错，因为输出行数少于输入行数。不过，得到的结果没有问题。

=head1 INSTALL

=head2 CPANMINUS

    $ cpanm App::Greple::tee

=head1 SEE ALSO

L<App::Greple::tee>, L<https://github.com/kaz-utashiro/App-Greple-tee>

L<https://github.com/greymd/teip>

L<App::Greple>, L<https://github.com/kaz-utashiro/greple>

L<https://github.com/tecolicom/Greple>

L<App::Greple::xlate>

=head1 BUGS

在连接韩文文本时，C<-fillup> 选项将删除韩文字符之间的空格。

=head1 AUTHOR

Kazumasa Utashiro

=head1 LICENSE

Copyright © 2023 Kazumasa Utashiro.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
