#keywords perl,commandline #title Perl Commandline CookBook = Perl Commandline CookBook = Perl은 많은 분야에서 강력한 힘을 가지고 있지만 쉘 커맨드 라인에서 기존의 awk와 sed등을 대체하고 그이상의 많은 일을 해낼 수 있는 강력한 도구입니다. 커맨드라인 펄은 "아는만큼 쓰면된다"는 펄의 장점을 보여주는 가장 좋은 예입니다. 커맨드 라인에서 쓸수 있는 다양한 Perl 팁을 모아봅시다. Perl외의 다양한 방법들도 함께 모아서 비교해보는 것도 좋겠죠? 바로 복사해서 쓸 수 있는 CookBook을 만드는 것이 목적인만큼 팁들을 문서의 앞으로 돌리고 문서의 뒤쪽에 커맨드라인 옵션이나 유용한 문법에 대해 추가하겠습니다. -- [pung96] [[DateTime(2007-01-31T14:30:27)]] [[TableOfContents]] == Perl Commandline 예제들 == === 많은 파일들을 한번에 삭제하기 === {{{ find -name "*.log" -print | perl -nle unlink find -name "*.log" -exec rm \{\} \; find -name "*.log" -print | xargs rm }}} -exec를 이용한 방법이 간단하기는 하지만 계속 새로운 프로세서를 띄어야 하기 때문에 perl을 이용하는 방법이 훨씬 빠릅니다. xargs 역시 받을 있는 인자의 개수가 한계가 있기 때문에 여러번의 프로세스를 띄어야 할 것으로 예상됩니다. perl은 인자로 받는것이 아니기 때문에 하나의 프로세스로 모두 해결할 수 있습니다. 1000개 지운후에 5초 쉬도록 할 경우 {{{ find -name "*.log" -print | perl -nle 'unlink; $.%1000==0 and sleep(10);' }}} * {{{$.}}}은 현재의 라인번호 변수입니다. === 여러줄의 데이터를 grep하기 === {{{ perl -0777ne '/(START_FLAG.*?END_FLAG)/s and print $1' list.txt # 파일이 작을때 perl -ne '/START_FLAG/ ... /END_FLAG/ and print;' # 파일이 클때 }}} === 리스트 비교 : 복잡한 comm 구현하기 === 기본 아이디어는 여러 파일을 읽어서 각 라인의 적당한 패턴 혹은 전체 라인을 해쉬 키로 만들고 라인을 해쉬 값으로 만들어서 각각 파일에 대응되는 해쉬에 저장한 후에 키가 각 해쉬에 존재하는지 확인하여 출력합니다. 편의상 스크립트에서 주로 사용하지 않는 심볼릭 레퍼런스를 사용했습니다. * 기본 리스트비교(comm) comm, grep 등을 이용한 쉬운 방법들이 많기는 하지만 패턴매치를 이용한 비교를 더 쉽게 이해하기 위해서 적어보았습니다. 게다가 제 경험상으로는 perl의 comm이나 grep보다 빨랐습니다(아마 메모리는 더 많이 사용할 것입니다.). {{{#!vim perl # list1 과 list2 모두에 있는 항목 grep -f list2 list1 perl -e '@a{@ARGV}=q(A..Z);while(<>){$a{$ARGV}->{$_}++};for(keys %A){print $_ if $B{$_}}' list1 list2 perl -ne 'BEGIN{@a{@ARGV}=(A..Z)}{$a{$ARGV}->{$_}++}END{for(keys %A){print $_ if $B{$_} } }' ls.log ls.log2 # list1 에만 있는 항목 grep -vf list2 list1 perl -e '@a{@ARGV}=(A..Z);while(<>){$a{$ARGV}->{$_}++};for(keys %A){print $_ unless $B{$_}}' list1 list2 # list1 + list2 cat list1 list2 | uniq perl -e 'while(<>){$A{$_}++};for(keys %A){print $_;};' # 속도는 좀 느리지만 간단한 방법 perl -e '@s{`cat OLD`}=( ); exists $s{$_} && print for `cat NEW`' }}} 1. {{{$a{@ARGV}=(A..Z)}}} : 인자들로 %A해쉬를 채웁니다. $a{첫번째인자}="A", $a{두번째인자}="B" 로 Z까지 채울 수 있습니다. 1. {{{$a{$ARGV}->{$_}++}}} : {{{<>}}}나 -n옵션으로 파일을 읽을때 현재 읽고있는 파일의 이름이 $ARGV로 할당됩니다. 이때 $a{$ARGV}는 위에서 할당한 것처럼 인자순서대로 A~Z값을 가지고 이 값을 심볼릭 레퍼런스로 이용하여 결국에는 첫번째 파일의 경우 %A에 두번째 파일은 %B를 사용합니다. 따라서 첫번째 파일의 경우 이 코드는 {{{%A{$_}++ }}} 로 해석됩니다. $_는 현재 라인 전체를 의미하므로 라인을 키로하고 값은 편의상 1을 더하는 방법을 씁니다. 1. 파일을 모두 읽어서 각 해쉬를 채운후 %A의 키들을 읽어서 각 키에대해 %B에도 값이 존재하는 키들을 출력하면 %A와 %B의 키 교집합을 구할 수 있습니다. * 패턴 매칭을 이용한 비교 {{{ pattern이 list1 과 list2에 모두 매치되는 항목의 list1 항목. 말이 좀 복잡하네요. perl -e '@A{@ARGV}=qw(L R);while(<>){/(pattern)/ and $A{$ARGV}->{$1}=$_};for(keys %L){print $L{$_} if $R{$_};}' list1 list2 }}} * 3중비교 {{{ perl -e '@a{@ARGV}=(A..Z);while(<>){/(pattern)/ and $a{$ARGV}->{$1}=$_};for(keys %A){print $A{$_} if $B{$_}&&$C{$_} }' list1 list2 }}} === 엑셀처럼 컬럼 계산하기 === {{{ cat data.txt | perl -ane '{$avr=$F[2]+$F[3];$sum+=$avr;print "Avr is $avr\n";}END{print "Sum is $sum\n";}' cat data.txt | awk '{avr=$1+$2;sum+=avr;print "Avr is "avr;}END{print "Sum is "sum;}' perl -nle '{/(pattern1).*(pattern2)/ and $avr=$1+$2 and $sum+=$avr and print "Avr is $avr"}END{print "Sum is $sum";}' data.txt }}} === 파일 수정하기 === * oldpattern을 newstring로 수정하고 기존의 파일은 *.bak로 백업합니다. {{{ perl -ibak -pe 's/oldpattern/newstring/g;' }}} === 각 라인의 패턴에 따라 다른 파일(pattern.txt)로 분류하기 === {{{ perl -ne '{/(pattern)/ and $H{$1}.=$_;}END{for(keys %H){open F,">$_.txt";print F $H{$_};close F;}' data.txt }}} * 파일 전체를 해쉬에 넣는 방법이므로 파일이 커지면 메모리를 많이 사용한다는 점에 유의해야 합니다. (요즘은 메모리가 커서 수백메가바이트의 파일도 처리할 수 있죠) === 서브디렉토리 grep하기 === {{{ grep -r pung96 * 에 대응되는 표현 find | perl -nle '$f=$_;-T $f or next;open(F,$f);while(){/pung96/ and print "$f : $_";}' }}} == Perl Commandline Option == == 참고문헌 ==