· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Perl Commandline CookBook

Perl Commandline CookBook

Perl은 많은 분야에서 강력한 힘을 가지고 있지만 쉘 커맨드 라인에서 기존의 awk와 sed등을 대체하고 그이상의 많은 일을 해낼 수 있는 강력한 도구입니다. 커맨드라인 펄은 "아는만큼 쓰면된다"는 펄의 장점을 보여주는 가장 좋은 예입니다.

커맨드 라인에서 쓸수 있는 다양한 Perl 팁을 모아봅시다. Perl외의 다양한 방법들도 함께 모아서 비교해보는 것도 좋겠죠?

바로 복사해서 쓸 수 있는 CookBook을 만드는 것이 목적인만큼 팁들을 문서의 앞으로 돌리고 문서의 뒤쪽에 커맨드라인 옵션이나 유용한 문법에 대해 추가하겠습니다. -- pung96 2007-01-31 23:30:27

1.1. Perl Commandline 예제들

1.1.1. 많은 파일들을 한번에 삭제하기

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);'
  • $.은 현재의 라인번호 변수입니다.

1.1.2. 여러줄의 데이터를 grep하기

perl -0777ne '/(START_FLAG.*?END_FLAG)/s and print $1' list.txt  # 파일이 작을때
perl -ne '/START_FLAG/ ... /END_FLAG/ and print;'               # 파일이 클때

1.1.3. 리스트 비교 : 복잡한 comm 구현하기

기본 아이디어는 여러 파일을 읽어서 각 라인의 적당한 패턴 혹은 전체 라인을 해쉬 키로 만들고 라인을 해쉬 값으로 만들어서 각각 파일에 대응되는 해쉬에 저장한 후에 키가 각 해쉬에 존재하는지 확인하여 출력합니다. 편의상 스크립트에서 주로 사용하지 않는 심볼릭 레퍼런스를 사용했습니다.
  • 기본 리스트비교(comm)
comm, grep 등을 이용한 쉬운 방법들이 많기는 하지만 패턴매치를 이용한 비교를 더 쉽게 이해하기 위해서 적어보았습니다. 게다가 제 경험상으로는 perl의 comm이나 grep보다 빨랐습니다(아마 메모리는 더 많이 사용할 것입니다.).
# 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까지 채울 수 있습니다.
  2. $a{$ARGV}->{$_}++ : <>나 -n옵션으로 파일을 읽을때 현재 읽고있는 파일의 이름이 $ARGV로 할당됩니다. 이때 $a{$ARGV}는 위에서 할당한 것처럼 인자순서대로 A~Z값을 가지고 이 값을 심볼릭 레퍼런스로 이용하여 결국에는 첫번째 파일의 경우 %A에 두번째 파일은 %B를 사용합니다. 따라서 첫번째 파일의 경우 이 코드는 %A{$_}++ 로 해석됩니다. $_는 현재 라인 전체를 의미하므로 라인을 키로하고 값은 편의상 1을 더하는 방법을 씁니다.
  3. 파일을 모두 읽어서 각 해쉬를 채운후 %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
      

    1.1.4. 엑셀처럼 컬럼 계산하기

    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
    

    1.1.5. 파일 수정하기

    • oldpattern을 newstring로 수정하고 기존의 파일은 *.bak로 백업합니다.
      perl -ibak -pe 's/oldpattern/newstring/g;'
      

    1.1.6. 각 라인의 패턴에 따라 다른 파일(pattern.txt)로 분류하기

    perl -ne '{/(pattern)/ and $H{$1}.=$_;}END{for(keys %H){open F,">$_.txt";print F $H{$_};close F;}' data.txt
    
    • 파일 전체를 해쉬에 넣는 방법이므로 파일이 커지면 메모리를 많이 사용한다는 점에 유의해야 합니다. (요즘은 메모리가 커서 수백메가바이트의 파일도 처리할 수 있죠)

    1.1.7. 서브디렉토리 grep하기

    grep -r pung96 *
    에 대응되는 표현
    find | perl -nle '$f=$_;-T $f or next;open(F,$f);while(<F>){/pung96/ and print "$f : $_";}'
    

    1.2. Perl Commandline Option

    1.3. 참고문헌




    sponsored by andamiro
    sponsored by cdnetworks
    sponsored by HP

    Valid XHTML 1.0! Valid CSS! powered by MoniWiki
    last modified 2007-09-06 09:13:11
    Processing time 0.0076 sec