=encoding utf-8

=head1 NAME

App::Greple::tee - 외부 명령 결과로 일치한 텍스트를 대체하는 모듈

=head1 SYNOPSIS

    greple -Mtee command -- ...

=head1 VERSION

Version 1.05

=head1 DESCRIPTION

Greple의 B<-Mtee> 모듈은 일치한 텍스트 부분을 지정한 필터 명령으로 보내고, 그 결과로 해당 부분을 대체합니다. 이 아이디어는 B<teip>라는 명령에서 유래했습니다. 부분 데이터를 외부 필터 명령으로 우회(bypass)하는 것과 비슷합니다.

필터 명령은 모듈 선언(C<-Mtee>) 뒤에 오며, 두 개의 대시(C<-->)로 종료합니다. 예를 들어, 다음 명령은 데이터에서 일치한 단어에 대해 C<a-z A-Z> 인자를 사용하여 C<tr> 명령을 호출합니다.

    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>

B<--discrete> 옵션을 사용하면 각 명령이 필요할 때 실행됩니다. B<--bulkmode> 옵션을 사용하면 모든 변환이 한 번에 수행됩니다.

=item B<--crmode>

이 옵션은 각 블록 중간의 모든 개행 문자를 캐리지 리턴 문자로 바꿉니다. 명령 실행 결과에 포함된 캐리지 리턴은 다시 개행 문자로 복원됩니다. 따라서 B<--discrete> 옵션을 사용하지 않고도 여러 줄로 구성된 블록을 일괄 처리할 수 있습니다.

이는 CR로 구분된 텍스트를 결합하고 CR로 구분된 접힌 줄을 출력하는 L<ansifold> 명령의 B<--crmode> 옵션과 잘 작동합니다.

=item B<--fillup>

필터 명령으로 전달하기 전에 연속된 비어 있지 않은 줄들을 하나의 줄로 결합합니다. 전각 문자(일본어, 중국어) 사이의 개행 문자는 삭제되고, 그 외의 개행 문자는 공백으로 대체됩니다. 한국어(한글)는 ASCII 텍스트처럼 취급되어 공백으로 결합됩니다.

=item B<--squeeze>

연속된 두 개 이상의 개행 문자를 하나로 합칩니다.

=item B<-ML> B<--offload> I<command>

L<teip(1)>의 B<--offload> 옵션은 다른 모듈 L<App::Greple::L> (B<-ML>)에서 구현되어 있습니다.

    greple -Mtee cat -n -- -ML --offload 'seq 10 20'

B<-ML> 모듈을 사용하여 다음과 같이 짝수 줄만 처리할 수도 있습니다.

    greple -Mtee cat -n -- -ML 2::2

=back

=head1 CONFIGURATION

모듈 매개변수는 다음 구문을 사용하여 B<Getopt::EX::Config> 모듈로 설정할 수 있습니다:

    greple -Mtee::config(discrete) ...
    greple -Mtee::config(fillup,crmode) ...

셸 별칭이나 모듈 파일과 함께 사용하면 유용합니다.

사용 가능한 매개변수: B<discrete>, B<bulkmode>, B<crmode>, B<fillup>, B<squeeze>, B<blocks>, B<nofork>.

=head1 FUNCTION CALL

외부 명령 대신, 명령 이름 앞에 C<&>를 붙여 Perl 함수를 호출할 수 있습니다.

    greple -Mtee '&App::ansifold::ansifold' -w40 -- ...

함수는 fork된 자식 프로세스에서 실행되므로 다음 요구 사항을 따라야 합니다:

=over 4

=item *

일치한 텍스트를 B<STDIN>에서 읽습니다

=item *

변환된 결과를 B<STDOUT>에 출력합니다

=item *

인수는 C<@ARGV>와 C<@_>를 통해 모두 전달됩니다

=back

완전히 한정된 함수 이름이라면 어떤 것이든 사용할 수 있습니다:

    greple -Mtee '&Your::Module::function' -- ...

모듈이 아직 로드되지 않았다면 자동으로 로드됩니다.

편의를 위해 다음의 짧은 별칭을 사용할 수 있습니다:

=over 4

=item B<&ansicolumn>

C<App::ansicolumn::ansicolumn>를 호출합니다.

=item B<&ansifold>

C<App::ansifold::ansifold>를 호출합니다.

=item B<&cat-v>

C<App::cat::v-E<gt>new-E<gt>run(@_)>를 호출합니다.

=back

함수 호출을 사용하면 각 호출마다 외부 프로세스를 fork하는 오버헤드를 피할 수 있으므로, B<--discrete> 옵션과 함께 사용할 때 성능을 크게 향상시킬 수 있습니다.

=head1 LEGACIES

B<greple>에 B<--stretch> (B<-S>) 옵션이 구현됨에 따라 B<--blocks> 옵션은 더 이상 필요하지 않습니다. 다음과 같이 간단히 수행할 수 있습니다.

    greple -Mtee cat -n -- --all -SE foo

향후 폐기될 수 있으므로 B<--blocks> 사용은 권장하지 않습니다.


=over 7

=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> 옵션을 함께 사용하지 마십시오. 블록이 전체 데이터가 되기 때문입니다.

=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\pP].+\n)+' tee.pm

위 명령에 B<-Mtee> 모듈을 결합하여 B<deepl> 명령을 호출하면 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> 명령을 사용하여 재포맷할 수 있습니다. 두 B<--crmode> 옵션을 함께 사용하면 여러 줄 블록을 효율적으로 처리할 수 있습니다:

    greple -Mtee ansifold -sw40 --prefix '     ' --crmode -- --crmode --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.

B<--discrete> 옵션도 사용할 수 있지만, 여러 프로세스를 시작하므로 실행에 더 오래 걸립니다.

=head1 EXAMPLE 3

헤더가 아닌 줄에서 문자열을 grep 하고 싶은 상황을 생각해 보십시오. 예를 들어 C<docker image ls> 명령에서 Docker 이미지 이름을 검색하되 헤더 줄은 남겨두고 싶을 수 있습니다. 다음 명령으로 할 수 있습니다.

    greple -Mtee grep perl -- -ML 2: --discrete --all

옵션 C<-ML 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>

L<App::ansifold>, L<https://github.com/tecolicom/App-ansifold>

=head1 AUTHOR

Kazumasa Utashiro

=head1 LICENSE

Copyright © 2023-2026 Kazumasa Utashiro.

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

=cut
