[재질문] Perl을 이용해 file open해서 그 파일에 대한 내용을 정규식 표현으로 추출을 해서 print할려 합니다.

skylovetoya의 이미지

이전에 같은 질문으로 제가 올렸었는데요.

도저히 답이 안나와서 다시 한번 질문을 드립니다. ㅠㅠ

일단 파일에 내용은

Hostname IP OS/ARC CPU/MEM
1. hostname1 bond0:192.168.0.1 (1000Mb/s) RedHat 5.8 x86_64 E5620@2.40GHz 24GB(2GB)
2. hostname2 bond0:192.168.0.2 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB)

ip를 넣으면 client에 정보가 log파일이 저장 됩니다.(위와 같이 저장이 됩니다.)

이걸 다시 불러와서 정규식 표현으로 추출을 해서 재출력을 하는 방식인데요.

print "Input Slave Server IP :\n";
        open my $snoarch, '>', $output;
        while (my $line = <STDIN>){
                last if $line =~ '^f$';
                print $snoarch $line;
        }
        close $snoarch;
 
        print "\n========================================================================================";
        print "\nHostname                    IP                   OS/ARC                  CPU/MEM\n";
 
        open $snoarch, '<', $output;
 
        while ($s_ip = <$snoarch>){
                $telnet->open($s_ip);
                #$telnet->login($suser,$spw);
                $telnet->login(@seuser);
                $telnet->print("su -");
                $telnet->waitfor('/password: ?$/i');
 
             $telnet->print($rpw);
                $telnet->prompt('/# $/');
                $telnet->waitfor($telnet->prompt);
 
       foreach($i < 50 ) {
        $i++;
        }
 
        my (@s_host,@s_ip,@snet_d,@s_ethtool,@s_os,@s_arc,@s_cpu,@s_mem,@s_swap);
 
        @s_host =  $telnet->cmd($host);
        chomp @s_host;
        pop @s_host;
 
 
        @s_ip = $telnet->cmd($iff);
        chomp @s_ip;
        pop @s_ip;
 
        @snet_d = $telnet->cmd($net_dev);
        chomp @snet_d;
        pop @snet_d;
 
        @s_ethtool = $telnet->cmd($eth_tool);
        chomp @s_ethtool;
        pop @s_ethtool;
 
        @s_os =  $telnet->cmd($os);
        chomp @s_os;
        pop @s_os;
 
 
        @s_arc =  $telnet->cmd($arc);
        chomp @s_arc;
        pop @s_arc;
 
 
        @s_cpu = $telnet->cmd($cpu);
        chomp @s_cpu;
        pop @s_cpu;
 
        @s_mem =  $telnet->cmd($mem);
        chomp @s_mem;
        pop @s_mem;
 
        @s_swap =  $telnet->cmd($swap);
        chomp @s_swap;
        pop @s_swap;
 
 
        ##Make a Logfile
 
        open my $s_log, '>>', $s_log_file;
        printf $s_log("$i. %-20s @snet_d:%-16s(@s_ethtool) RedHat %-s%-15s %-5s %-sGB(%-sGB)\n","@s_host","@s_ip","@s_os","@s_arc","@s_cpu","@s_mem","@s_swap");
        close $s_log;
 
        open (S_FILE, "+<$s_log_file") or die "open failed!\n"; ## 해당 log파일을 open합니다.
 
        while (my $line =<S_FILE> ) ##한줄씩 읽어 나가게 while문으로 덮어주고,
        {
        my $as5 = /5.8/; ##위 log파일 내용중에 5.8버젼만 추출합니다.
 
        if ( $line =~ /^1./) ##처음에는 log파일에 단순히 /5.8/ 요 내용만 가져 갈려 했는데 도저히 답이 안나와서 1. 2. 3. 이런식으로 구분을 라인마다 주었습니다.
        {
        my $num = $1;
 
                if ( $line =~ /$as5/  ){ ##매칭시킵니다.
                $num, printf ("%-20s @snet_d:%-16s(@s_ethtool) RedHat %-s%-15s %-5s %-sGB(%-sGB) Matched!\n","@s_host","@s_ip","@s_os","@s_arc","@s_cpu","@s_mem","@s_swap"); ##각각 client에 호스트 네임 / ip / OS / 아키택쳐 등에 정보를 가지고 있는 배열입니다.
                }else{
                $num, printf("%-20s @snet_d:%-16s(@s_ethtool) RedHat %-s%-15s %-5s %-sGB(%-sGB) Does Not Matched!\n","@s_host","@s_ip","@s_os","@s_arc","@s_cpu","@s_mem","@s_swap");
                }
        }
        close (S_FILE);
        }
}
close $snoarch;
}

이런식인데,

이걸 어떻게 해야 라인 별로 매칭 시켜서 출력이 가능할까요?
(해당 스크립트 실행 후 결과는 맨 윗라인이 참이면 전부 matched가 되어버리네요 ㅠㅠ)
저대로 실행을 한 결과는

Hostname IP OS/ARC CPU/MEM
hostname1 bond0:192.168.0.1 (1000Mb/s) RedHat 5.8 x86_64 E5620@2.40GHz 24GB(2GB) Matched! ##첫번째 줄
hostname2 bond0:192.168.0.2 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB) Matched! ##두번째 줄
hostname3 bond0:192.168.0.3 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB) Matched! ##세번째 줄
hostname4 bond0:192.168.0.4 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB) Matched! ##네번째 줄

이렇게 전부 Matched가 되어버립니다. 두번째에서 네번째 줄은 5.7버젼이면 Does Not Matched가 출력이 되어야합니다. 아래와 같이요.

제가 원하는 결과는

Hostname IP OS/ARC CPU/MEM
hostname1 bond0:192.168.0.1 (1000Mb/s) RedHat 5.8 x86_64 E5620@2.40GHz 24GB(2GB) Matched!
hostname2 bond0:192.168.0.2 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB) Does Not Matched!
hostname3 bond0:192.168.0.3 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB) Does Not Matched!
hostname4 bond0:192.168.0.4 (1000Mb/s) RedHat 5.7 x86_64 E5620@2.40GHz 24GB(2GB) Does Not Matched!

이렇게 나왔으면 좋겠습니다..ㅠㅠ

그러니까 log파일을 불러와서 첫번째 라인 매치해서 5.8이 맞으면 Matched!가 print되고 다음 두번째 줄 매치한다음 (위예제는 5.7이니) Does Not Matched! 이렇게 print되게 하고

그 다음도 역시 세번째줄 매칭... 이렇게 하는것이 목적입니다. (회사 일 특성상 중요해서요 ㅠ_ㅠ)

고수분들에 의견 부탁드립니다!!

처음에는 log file vs log file로 매칭하려 했는데 이것도 마찬가지더라구요.

p.s raymundo님 저번에 답변 감사했습니다. 근데 제가 원하던 답은 못구해서 이번에 전체 코드를 올려봅니다.

--------------------

행복한 주말 되세요!

raymundo의 이미지

1.

KLDP 게시판은 답글이 달리면 다시 목록 위로 올라오니까, 한 가지 문제는 한 게시물에서 이어나가시는 게 좋습니다.

2.

어차피 로그 파일이 정말 쓰신 것처럼 저장된다면 매칭은 별개의 문제니까 앞 코드는 딱히 필요는 없어 보입니다만, 그나마도 어째 코드들이 이상한게...

예를 들어 그저 $i를 50까지 증가시키는 무의미한 foreach 루프의 경우는 그냥 $i = 50 하면 되는 거고,

그리고 이 상태라면 로그 파일이 한 줄 쓰일 때마다 로그 파일 전체를 읽으려고 하고 있고, 그나마도 close(S_FILE)이
while 루프 안에 있으니까 로그파일 첫 줄만 읽고 더 읽지 못했을 텐데요.

코드에 공개할 수 없는 부분이 있어 지우는 건 어쩔 수 없는데 최소한 루프나 조건문의 블럭 구조는 정확히 맞춰주셔야 될 것 같습니다.

3.

이제 문제의 매칭 말인데,

일단 로그 파일은 본문에 적어주신 대로 정확히 기록되었다고 하고

Hostname IP OS/ARC CPU/MEM
1. hostname1 bond0:192.168.0.1 (1000Mb/s) RedHat 5.8 x86_64 <a href="mailto:E5620@2.40GHz" rel="nofollow">E5620@2.40GHz</a> 24GB(2GB)
2. hostname2 bond0:192.168.0.2 (1000Mb/s) RedHat 5.7 x86_64 <a href="mailto:E5620@2.40GHz" rel="nofollow">E5620@2.40GHz</a> 24GB(2GB)

지난 번 제 답글의 코드는 정확히 이걸 매치 검사를 하고 있는데요.

can not extract version  - 첫 줄
5.8 matched! - 둘째 줄
5.7 does not matched - 셋째 줄

출력할 때 라인 내용을 그대로 출력시키고 싶으면 $line 내용만 그대로 다시 출력해주면 될 일이고요.

뭐가 문제인가요?

4.

본문의 코드의 경우는,

    open (S_FILE, "+<$s_log_file") or die "open failed!\n"; ## 해당 log파일을 open합니다.
 
    while (my $line =<S_FILE> ) ##한줄씩 읽어 나가게 while문으로 덮어주고,
    {
        my $as5 = /5.8/; ##위 log파일 내용중에 5.8버젼만 추출합니다.
 
# 일단 여기가 문제인데,
# 첫째로 정규식의 마침표는 아무 글자에나 매칭되니까 이 정규식은 568, 5a8 등에도 매치될 겁니다. 5\.8 이어야 하고
# 둘째로 $as5 = /5.8/ 이것은 /5.8/의 결과를 $as5 에 담게 되고 /5.8/ 은 매치 연산자니까 디폴트 변수가 생략된 형태라서
# $as5 = ( $_ =~ /5.8/ ) 로 해석이 되고, $_ 가 매치되지 않을 가능성이 매우 크니 $as5 는 거짓, 즉 빈스트링이 될 겁니다.
# $as5 가 빈 스트링 ""이니까, 이 아래 $line =~ /$as5/ 는 $line =~ // 와 같고, 무조건 매치됩니다.
# 5.8 을 변수에 두고 싶으시면
$as5 = '5\.8';   # 문자열로 저장하고
$line =~ /$as5/; # 검사를 하거나
 
$as5 = qr/5\.8/;  # 정규식 객체로 저장하고
$line =~ $as5;    # 검사를 하거나
# 하세요.
 
 
        if ( $line =~ /^1./) ##처음에는 log파일에 단순히 /5.8/ 요 내용만 가져 갈려 했는데 도저히 답이 안나와서 1. 2. 3. 이런식으로 구분을 라인마다 주었습니다.
 
# 이것도 납득이 안 가는데, 이러면 오직 "1"로 시작하는 라인만 검사하고 다른 라인은 아예 검사도 안 하고 통과했을텐데요.
# $line =~ /^\d+\./ 이래야 제일 앞에 숫자가 오고 그 뒤에 마침표가 오는 라인들에 대해 검사했을 겁니다.
 
 
        {
            my $num = $1;
 
            if ( $line =~ /$as5/  ){ ##매칭시킵니다.
 
# 위에서 말씀드렸듯이 이 조건은 무조건 매치되고
 
                $num, printf ("%-20s @snet_d:%-16s(@s_ethtool) RedHat %-s%-15s %-5s %-sGB(%-sGB) Matched!\n","@s_host","@s_ip","@s_os","@s_arc","@s_cpu","@s_mem","@s_swap"); ##각각 client에 호스트 >네임 / ip / OS / 아키택쳐 등에 정보를 가지고 있는 배열입니다.
 
# 뭐하러 이렇게 힘들게 출력하나요? 그냥 $line 을 출력하면 그만이잖아요?
# 단지 힘든 게 문제가 아니라.. 지금 보면 $line 은 로그 파일을 읽고 있는데 @s_ip, @s_arc, @s_swap 등은
# 방금 읽은 $line 에서 뽑은 게 아니라 저 위의 telnet 명령을 통해 뽑은 값이니까
# 이건 매치가 참이든 거짓이든 간에 해당 라인을 출력하는 게 아니라 전혀 엉뚱한 내용을 출력할 것입니다.
 
            }else{
                $num, printf("%-20s @snet_d:%-16s(@s_ethtool) RedHat %-s%-15s %-5s %-sGB(%-sGB) Doe
s Not Matched!\n","@s_host","@s_ip","@s_os","@s_arc","@s_cpu","@s_mem","@s_swap");
            }
        }
        close (S_FILE);
 
# 위에서 말씀드렸듯이 close 가 while 루프 안에 있는 것도 말이 안 되고요.
 
    }

그러니 결과적으로 이 모든 오류가 합쳐져서... (코드를 정말로 그대로 옮긴 거라면)

1)로그 파일에 한 줄 추가할 때마다 다시 로그파일을 처음부터 읽어서 매치 여부를 출력하는데
2)오직 로그 파일의 첫줄밖에 안 읽고 있고
3)로그 파일 첫줄은 "1. hostname1 bond0:192.168.0.1 (1000Mb/s) RedHat 5.8 x86_64 E5620@2.40GHz 24GB(2GB)" 이니까 이건 매치가 되는데 (게다가 사실은 뭐가 와도 매치될 것이고)
4)출력할때는 방금 읽은 라인을 출력하지 않고 좀 전에 로그 파일에 추가한 값들을 출력하고 있으니까 마치 두번째, 세번째, 네번째 라인을 읽어서 검사한 것처럼 사용자를 속이고 있는 거죠.

라인 매치가 문제가 아니라 일단 프로그램 흐름부터 다시 검토하시는 게 좋겠습니다.

좋은 하루 되세요!

skylovetoya의 이미지

레이문도님 답변 정말 감사합니다 ㅠㅠ

이제야 답을 찾은듯합니다!!!!

정말정말 감사합니다ㅠㅠㅠㅠㅠㅠㅠㅠ

우선 집에선 서버 환경이 안돼어서 전에 레이문도 님께서 알려주신 방법대로 다시 차근히 해보니 답이 나왔네요 ㅠㅠ

내일 회사 출근해서 다시 차근히 적용 시켜보겠습니다.

금같은 시간 내주시면서 섬세한 댓글 달아주셔서 감사합니다.

-----

늘 행복하시구 건강하세요!!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.