find
명령이 항상 지정된 디렉토리 대신 루트 디렉토리로 이동하는 이유를 누구라도 말해 줄 수 있습니까 $srceDir
?
my $srceDir = "/mnt/SDrive/SV/Capture Data/";
my $find_cmd = 'find $srceDir -type f -newermt 2013-02-14 ! -newermt 2013-02-15';
open(FIND_FILE, "$find_cmd |");
while(<FIND_FILE>){
next if /^total/; # because we're only interested in real output
print $_;
}
답변1
큰따옴표 대신 작은따옴표를 사용하기 때문입니다.
펄은 그렇지 않다작은따옴표로 묶인 변수 삽입, 그래서 당신이 하는 일은 '$srceDir' 문자열을 셸로 보내는 것입니다. 이 문자열은 환경 어딘가에 설정하지 않는 한 일반적으로 설정 해제(비어 있음)됩니다.
이 시도:
my $find_cmd = "find $srceDir -type f -newermt 2013-02-14 ! -newermt 2013-02-15";
아니면 더 나은 방법은 다음과 같습니다.
my $find_cmd = sprintf
'find "%s" -type f -newermt 2013-02-14 ! -newermt 2013-02-15',
$srceDir;
...공간을 배려하면서찾기 명령forked 에서 실행됩니다 sh
.
*중요사항*
@vonbrand가 올바르게 언급했듯이 :진주프로그램과 다른 많은 것들 사이의 통신을 보장하기 위해 실제로 많은 라이브러리가 제공됩니다.
파일 시스템 작업을 위해 find
Perl은 File
라이브러리 모듈을 사용합니다. 이를 위해 명령줄을 작은 Perl 스크립트로 변환하는 작은 File::Find
유틸리티가 있습니다 .find2perl
find
$ find2perl -type f -mtime -3 ! -mtime -2;
#! /usr/bin/perl -w
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if 0; #$running_under_some_shell
use strict;
use File::Find ();
# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.
# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
sub wanted;
# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '.');
exit;
sub wanted {
my ($dev,$ino,$mode,$nlink,$uid,$gid);
(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
-f _ &&
(int(-M _) < 3) &&
! (int(-M _) < 2)
&& print("$name\n");
}
따라서 귀하의 요구 사항은 다음과 같을 수 있습니다.
#! /usr/bin/perl -w
my $srceDir = "/mnt/SDrive/SV/Capture Data/";
my $startDate = "2013-02-14";
my $endDate = "2013-02-15";
use strict;
use File::Find ();
use POSIX qw|mktime|;
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
my ($sDay,$eDay)=map {
my ($year,$month,$day)=split("-",$_);
(time()-mktime(0,0,0,$day,$month-1,$year-1900))/86400
} ($startDate,$endDate);
sub wanted {
my ($dev,$ino,$mode,$nlink,$uid,$gid);
(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
-f _ &&
(-M _ < $sDay) &&
! (-M _ < $eDay)
&& print("$name\n");
}
File::Find::find({wanted => \&wanted}, $srceDir );
이것의 가장 큰 장점은 open $fh,"find ...|"
매우 강력하다는 것입니다. 파일 이름에 있는 문자(공백, 따옴표, 앰퍼샌드 등)에 신경 쓸 필요가 없습니다.
답변2
셸 메타 문자(예: 공백)가 포함된 문자열을 명령에 제공하면 셸 명령줄로 해석됩니다. 이는 다음 두 가지를 의미합니다.
- 추가 명령을 실행해야 하는데(명령줄을 구문 분석하기 위한 셸) 이는 그다지 효율적이지 않습니다. 일부 셸 구현의 경우 이는 추가 프로세스를 의미하기도 합니다.
- 특수 문자를 셸로 이스케이프해야 합니다.
매개변수 목록을 작성하기 위해 명령행을 분할하도록 쉘에 요청하는 것보다 매개변수 목록을 제공하여 명령을 직접 실행하는 것이 더 좋습니다.
또한 다음을 사용하지 않으면 -print0
출력을 안전하게 후처리 할 수 없습니다.find
비슷한 질문에 대한 내 대답, 다음과 같이 작성해야 합니다.
my $srceDir = "/mnt/SDrive/SV/Capture Data";
my @find_cmd = ("find", $srceDir, "-type", "f", "-newermt", "14 Feb 2013", "-print0");
open FIND, "-|", @find_cmd;
$/ = "\0"; # set perl's record separator
while (<FIND>) {
...
}
close FIND or warn $! ?
"Error closing find pipe: $!" :
"find exited with non-zero exit status: $?";
(그런데 라인을 find
출력하지 않으면 total
혼란스러울 수 있습니다 ls
.)