Perl 스크립트에서 find 명령을 사용하는 방법은 무엇입니까?

Perl 스크립트에서 find 명령을 사용하는 방법은 무엇입니까?

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가 올바르게 언급했듯이 :프로그램과 다른 많은 것들 사이의 통신을 보장하기 위해 실제로 많은 라이브러리가 제공됩니다.

파일 시스템 작업을 위해 findPerl은 File라이브러리 모듈을 사용합니다. 이를 위해 명령줄을 작은 Perl 스크립트로 변환하는 작은 File::Find유틸리티가 있습니다 .find2perlfind

$ 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

셸 메타 문자(예: 공백)가 포함된 문자열을 명령에 제공하면 셸 명령줄로 해석됩니다. 이는 다음 두 가지를 의미합니다.

  1. 추가 명령을 실행해야 하는데(명령줄을 구문 분석하기 위한 셸) 이는 그다지 효율적이지 않습니다. 일부 셸 구현의 경우 이는 추가 프로세스를 의미하기도 합니다.
  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.)

관련 정보