find 명령을 사용하여 Perl에 인수를 전달할 수 있습니까?

find 명령을 사용하여 Perl에 인수를 전달할 수 있습니까?

Perl 스크립트가 있습니다

$ cat ~/script.pl
sub main {

    my ($file) = @_;

    <STUFF>

    }

}

foreach (@ARGV) {

    main($_);

}

디렉토리의 ~/script.pl모든 파일을 실행하고 싶습니다. 다음 명령을 사용하여 파일 목록을 가져올 수 있습니다.txt~/foo.txt~/foo

$ find ~/foo -type f -name \*.txt

어떻게든 이 명령을 사용하여 이러한 파일을 내 스크립트에 전달할 수 있습니까?

답변1

예, 명령을 사용하여 이를 수행하는 방법에는 여러 가지가 있습니다 find. 귀하의 상황을 이해하는 데 중요하다고 생각되는 순서대로 몇 가지를 나열하겠습니다.

  1. 귀하의 스크립트는 여러 파일 이름 인수를 허용하는 것으로 보이므로 find이 명령을 사용하여 이를 수행하는 가장 효율적이고 거의 보편적인 방법은 다음과 같습니다.

    find ~/foo -type f -name \*.txt -exec perl ~/script.pl {} +
    

    이렇게 하면 발견된 파일 이름 인수를 최대한 많이 사용하여 스크립트가 실행됩니다. 모든 파일 이름을 처리해야 하는 경우 스크립트가 여러 번 호출됩니다. 줄 +끝에 .

  2. 이것은 가장 독창적이고 다재다능한 방법입니다. 이는 perl발견된 각 파일에 대해 한 번 호출되므로 귀하의 경우에는 덜 효율적입니다. 이 사용법은 다음에서 유래합니다.유닉스의 초창기. \;줄 끝에 있는 이스케이프된 세미콜론( )을 확인하세요 ( +위의 반대).

    find ~/foo -type f -name \*.txt -exec perl ~/script.pl {} \;
    
  3. 이 명령은 -exec ... +구문이 에 추가되기 전에 파일 이름이나 기타 매개변수 목록으로 작업할 때 효율성을 높이기 위해 고안되었습니다 . 이는 위의 예와 거의 동일합니다.findxargs-exec ... +

    find ~/foo -type f -name \*.txt -print | xargs perl ~/script.pl
    

    구현에서 이를 지원하는 경우 인수 뿐만 아니라 -print0옵션도 사용해야 합니다 . 이로 인해 인수 문자열 사이에 널 문자가 인쇄되고 인수가 널 문자 이외의 다른 것으로 분할되는 것을 방지할 수 있습니다. 이는 파일 이름에 공백이나 기타 특수 문자가 포함된 경우 인수가 잘못 분할되는 것을 방지하는 데 도움이 됩니다.find-0xargsfindxargsxargs

    일반적으로 구문을 사용하는 것이 -exec ... +더 나은 방법입니다. 이렇게 find하면 파일 이름을 스크립트의 인수 목록에 직접 추가하여 프로세스를 제거하고 xargs. 매뉴얼 페이지를 xargs참조하십시오 .xargs

  4. find2perl또한 동일한 인수를 사용하여 동일한 작업을 수행하는 프로그램을 find인쇄하는 이 명령을 볼 수도 있습니다 . 그런 다음 생성된 코드를 스크립트에 perl통합할 수 있습니다 . perl아래 생성된 스크립트에서는 대신 함수 호출 옆의 마지막 줄을 수정합니다 print.

    $ find2perl foo -type f -name \*.txt    # /*
    
    #[some preamble code removed for brevity]
    
    # Traverse desired filesystems
    File::Find::find({wanted => \&wanted}, 'foo');
    exit;
    
    sub wanted {
        my ($dev,$ino,$mode,$nlink,$uid,$gid);
    
        (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
        -f _ &&
        /^.*\.txt\z/s
        && print("$name\n");
    }   
    

답변2

다른 답변에서 알 수 있듯이 가능합니다.

나는 대안을 제안하고 싶습니다. 이렇게 하지 말고 내장된 Perl을 사용하십시오. File::Find기본적으로 동일한 작업을 수행하지만 독립형으로 수행할 수 있습니다.

예를 들어:

#!/usr/bin/env perl
use strict;
use warnings;

use File::Find;

sub process {
    return unless -f;
    return unless m/\.txt$/; #regex style, not shell glob. 
    print "Found: Name of $_ as path $File::Find::name in $File::Find::dir\n"; 
}

find ( \&process, '~/foo' ); 

~/foopath()를 하드코딩하거나 에서 가져올 수 있습니다 @ARGV.

 find ( \&process, @ARGV ); #takes as many paths as you specify as args. 

답변3

-exec scriptName.sh {} \;응, 구조 가 있어

귀하의 구체적인 경우에는

find ~/foo -type f -name \*.txt -exec scriptName.sh {} \;

또 다른 방법은 빈 구분 기호를 사용하여 파일을 전달하는 것입니다 xargs.

이 예는 xargs 매뉴얼에서 직접 가져온 것입니다.

 find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f

관련 정보