[PERL] 특정폴더안에 있는 모든 파일을 불러들여 조건이 맞는 파일을 하나로 만드는 코드를 작성중입니다.
글쓴이: momo7 / 작성시간: 수, 2013/05/15 - 10:59오전
처음에 이곳 게시판을 빌어 많이 도움을 받았습니다. 어느정도 혼자 필요한 것은 할 수 있을 것이라 생각했는데,
10시간을 넘게 고민해보고, 고쳐봐도 잘 안되네요.
인터넷을 방황하다가, 폴더안에 있는 파일을 모두 합치는 소스를 이용하여, 수정을 하고 있습니다(수정중이기 때문에 일부 불필요한 코드가 있을 수 있습니다. 양해부탁드려요).
제가 가지고 있는 데이터는 한 폴더에 2011년 1월 1일부터 2099년 12월 30일까지의 데이터를 가지고 있습니다.
그 중에 같은 연도에 해당하는 파일의 특정 줄을 합쳐서 하나의 파일로 만드는 과정입니다.
루틴을 돌리고자 아래 코드를 사용하였습니다. $b =2011 ~ 2099
if (substr($file,17,4) eq $b){
문제는 하나의 조건 즉 2011년 데이터를 만족하는 것은 커맨드 창에서 파일 저장 기능을 사용해서 가능하였습니다만,
펄 내부에서 저장파일을 만들어서 저장하려고 하니, 제대로 먹히질 않습니다.
혹시 아래 코드를 보시고 고쳐주실 수 있으신분 있으신가요?
폴더내 파일을 같은 년도별로 분류시켜, 다시 그 폴더내용을 합치는 방법도 고려하고 있으나,
더 공부해보고자 하는 마음에 이렇게 올립니다.
use 5.010; use warnings; if( $#ARGV < 0 ) { die "폴더이름이 필요해요.\n"; } $dirName = shift(@ARGV); local($i); #서브폴더 및 파일 탐색 루틴 시작 &readSubDir($dirName); sub readSubDir { if(!opendir(dirHandle, $_[0])) { print "$_[0] Failed opening.\n"; return 0; } local(@files) = readdir(dirHandle); local($i); local($newFile); local(@dironly); local(@fileonly); for($i = 0; $i <= $#files; $i++) { $newFile = $_[0]."\\".$files[$i]; if(-d $newFile) { push(@dironly, $files[$i]); } elsif(-f $newFile) { push(@fileonly, $files[$i]); } else {} } @files = @dironly; push(@files, @fileonly); closedir dirHandle; my $out_file_template = 'newfile_2b_part_%06d.txt'; my $counter = 1; my $out_fh; for($i =0; $i <= $#files; $i++){ my $b = 2011; $newFile = $_[0]."\\".$files[$i]; if(-f $newFile){ open(fileHandle, $newFile)|| die "Cannot open 개체 \n"; my($dir, $file, $ext) = ($newFile =~ m|^(.*\\)(.*)(\..*)$| ); my(@fhs); if (substr($file,17,4) eq $b){ #if (!$out_fh) { #open $out_fh , '>' , sprintf( $out_file_template, $counter++ ) or die $!; if (substr($file,17,4) eq $b){ while(<fileHandle>){ if($. == 7){ print $out_fh $_; } } } } } } close( $out_fh ); }
Forums:
그동안 수정한 소스 및 데이터 샘플입니다. 역시 최종 파일만 저장이 되버리네요 ㅠ
use 5.010; use warnings;
if( $#ARGV < 0 ) { die "폴더이름이 필요해요.\n"; }
$dirName = shift(@ARGV); local($i);
&readSubDir($dirName);
sub readSubDir { if(!opendir(dirHandle, $[0])) { print "$[0] Failed opening.\n"; return 0; }
코드는 코드 태그를 이용하세요. 저렇게 해두면
코드는 코드 태그를 이용하세요.
저렇게 해두면 귀찮아서라도 안 보게 되요
말씀해주신것을 하는게 쉽지 않네요...
코드 태그를 이용하는 방법을 잘 몰랐습니다. 다음에는 잘 찾아보고 해야겠네요.
코멘트 감사합니다 ^^
음 ..
꼭 perl 을 써야 하는 상황이 아니라면..
7번째 라인만 같은 연도에 해당하는 파일로 저장.
코드 태그를 쓰면.. >> 가 >> ; 로 표시되는군요. (>> 로 써야함)
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
답변 감사합니다.
완벽한 기능은 아니지만, 일단 내용들을 묶어내는건 가능하겠네요.
개개 파일의 특정 줄에 있는 정보만을 추출해서 저장하고 싶어서 이래 저래 찾아보고 있는데
쉽지 않네요. 또, 윈도우만 사용해봐서 도와주신 내용을 어떻게 적용해 봐야할지는 다시 찾아보고 공부해보겠습니다.
perl로도 님께서 작성해주신 것까지는 해결했습니다(완벽한 코드는 아니지만),
다시 한번 감사드립니다.
음 ..
windows 에서 perl 을 쓰시나 보군요.
저건 그냥 shell script 에 sed 를 쓴거라.. windows 에서 쓰시려면 bash-win32, sed-win32 가 필요합니다.
아니면 그냥 linux 에서 실행하시거나...;;
perl 은 잘은 모르겠지만.. 파일을 append 가 아닌 create 모드로 open 하신 것 때문에 마지막 내용만 저장된 것 같군요.
이미 해결하셨다니 다행입니다.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
갑사합니다 append 모드를 찾아보니 해결되는군요^^
open OUT, ">$filename" or die "Failed to create $filename";
위 수정된 부분에 있는 소스를 커멘트 참고하여 아래와 같이 수정하니, 해결이 되네요.. 킁~
open OUT, ">>$filename" or die "Failed to create $filename";
10시간의 고민이 한방에 해결되었습니다. 정말 감사합니다.
perl을 포함하여 프로그래밍 언어를 공부한지 얼마 되지 않아서 한번 막히면 참 막막하더라구요...
감사합니다.~~~
본문의 코드 정리해 드렸습니다.
본문의 코드 정리해 드렸습니다.
감사합니다.
감사합니다. 훨씬 깔끔하고 가독성이 좋네요^^ 앞으론 잘 해놓겠습니다.
디렉토리 순회를 복잡하게 수동으로 할 필요 없이
Perl 코어모듈인 File::Find 모듈( http://perldoc.perl.org/File/Find.html )을 사용하면
더 간단하게 할 수 있습니다.
(위 코드에서 > & gt;로 나오는건 >> 입니다. 이상하게 보여주네요)
그리고 위 코드에서 local변수에 대해 사용법을 혼돈하시는 것 같은데 위의 경우에는 my변수를 쓰면 됩니다.
Perl에서 한줄 짜리 코딩이 아니라면 use strict;를 넣어주시고
my our local state 변수를 확실히 이해하시고 사용하시길 추천드립니다.
참고:
http://ko.perlmaven.com/scope-of-variables-in-perl
http://www.slideshare.net/xSawyer/our-local-state-my-my-understanding-perl-variables
폴더내 파일을 루틴으로 찾아서 하는 부분은 다른 분이 만드신 코드를 활용한 것이였습니다.
폴더내 파일을 루틴으로 찾아서 하는 부분은 다른 분이 만드신 코드를 활용한 것이였습니다.
출처가 기억나지 않았는데, 좋은 가르침 감사합니다.
어제, 그제는 엄청 고민하면 작성했는데, 한계가 있는(연도가 연속되지 않으면 찾아내지 못하는) 코드였는데
님코드와 아래 답변을 달아주신 님의 코드를 보고 배웠습니다.
감사합니다.
7번째 줄만 읽으면 되는 경우라면, 그 뒷부분은 더
7번째 줄만 읽으면 되는 경우라면,
그 뒷부분은 더 읽을 필요가 없을 것 같아요. ^^
설명을 보니, find(\&wanted, @directories); 에서...
For each file or directory found, it calls the &wanted subroutine. 파일이나 디렉토리마다 wanted 함수를 실행한다고 하니...
file을 매번 열고 닫지 말고, 필요할 때 열고, 한꺼번에 닫으면 어떨까요? ^^
aero님이 멋진 해결책을 주셨는데, 해결 되니 성능 욕심이 생기네요.
원하시는대로 고쳐봤습니다.
전역변수 %F 를 이용해서 이미 만들어져서 열린파일은 다시 열지않는 방식으로 했습니다.
그리고 perl에서 루프탈출은 break가 아니고 last죠? :)
고맙습니다. ^^
고맙습니다. ^^
대충 봤습니다만... 특정 폴더내에 파일들의 이름에
대충 봤습니다만...
특정 폴더내에 파일들의 이름에 연도가 포함되어있고.
그 연도를 기준으로 그룹핑을 해서 각 파일의 7번째 라인만 새로운 파일에 합친다...??
이게 맞다면 아래의 코드도 동작 할 것으로 예상됩니다.
* 새로 생성되는 파일을 해당 디렉토리내에서 만들게 되면 다음번 readdir 혹은 glob 으로 다시 읽어들일수 있기
때문에 새로운 파일은 작업디렉토리의 상위 디렉토리에 생성하게 했습니다.
#!/usr/bin/env perl
use strict;
use warnings;
my ($dir) = @ARGV;
chdir $dir or die "Can't change directory($dir) : $!\n";
## 작업 디렉토리에서 파일만
my @files = grep { -f } glob '*';
foreach my $file (@files) {
open my $fh, '<', $file
or die "Can't read the file($file) : $!\n";
my $year = substr $file, 17, 4;
while (<$fh>) {
## 7번째 라인일경우 처리후 루프 종료
if ( $. == 7 ) {
open my $fh_a, '>>', "../$year.txt"
or die "Can't open the file($_) : $!\n";
print {$fh_a} $_;
close $fh_a;
last;
}
}
close $fh;
}
감사합니다. 원하던 결과였습니다.
위에 커멘트를 보고 저도 특정연도 파일만 있을때도 가능한 코드를 짜보려고
고민해보다가 잠이 들었었는데, 님의 코드를 사용해서 하니, 제가 원하는 결과가 나타났습니다.
많이 배웠습니다~~
하나 더...
파일명에서 획득한 $year가 정말로 연도 인지 확인하면 더 좋겠네요...
foreach my $file (@files) {
open my $fh, '<', $file
or die "Can't read the file($file) : $!\n";
my $year = substr $file, 17, 4;
.
.
.
foreach my $file (@files) {
my $year = substr $file, 17, 4;
next unless $year =~ /20\d\d/;
open my $fh, '<', $file
or die "Can't read the file($file) : $!\n";
.
.
.
댓글 달기