Unix는 여러 가지 자두와 유형 fs에 압도됩니까?

Unix는 여러 가지 자두와 유형 fs에 압도됩니까?

나는 이 루빅스 큐브 작업에 며칠을 보냈습니다. 한 문제를 해결하기 위해 내가 하는 모든 일은 다른 문제를 파괴합니다.

POSIX 호환 MacOS X 10.5~10.14를 사용하고 있습니다. Perl 스크립트의 맥락에서 이를 호출합니다.

  system ("find blah blah > FILENAME");

이 모든 작업을 동시에 수행하려면 Unix '찾기'가 필요합니다.

  • 볼륨의 루트에서 시작합니다./Volumes/My HD
  • 파일 시스템을 교차하지 마십시오
  • 디렉토리나 심볼릭 링크가 아닌 파일만 인쇄합니다.
  • 내려가지도 마세요많은 종류의.net dev system개발자/github/twonky/)
  • 시작점에는 공백이 포함될 수 있습니다.

지금은 다음을 수행하고 있습니다. (가독성을 위해 여러 줄로 나누었습니다. 실제로는 하나의 긴 줄입니다.)

 Find -x '/Volumes/foo/' 
    -path '/Volumes/foo//dev/*' -prune
    -path '/Volumes/foo//net/*' -prune
    -path '/Volumes/foo//system/*' -prune
    -o -type f -print

이중의 이유는 /찾다의 출력에는 //가 포함됩니다. 시작점이 /로 끝나기 때문입니다. 자르기 경로는 일관되어야 하며 그렇지 않으면 일치하지 않습니다. 시작점이 /로 끝나는 이유는 무엇입니까? 왜냐면 그렇지 않으면,찾다"My HD"와 같이 이름에 공백이 포함된 시작점에서는 실패합니다. 그것을 시도했다.

현재 찾기에서는 목록의 첫 번째 디렉터리만 제외됩니다. 나머지는 그냥 무시합니다. 현재 OS X 10.5에서 테스트 중이지만 어디에서나 작동할 수 있는 것이 필요합니다.

다중 트리밍 + 파일만 + 파일 이름의 공백이 너무 멀습니까? 내가 너무 많은 것을 요구하고 있는 걸까?찾다?

답변1

두 번째 일치를 완료하려면 "or"가 필요합니다. 두 가지 모두와 일치할 수 있는 경로는 없습니다 -path '/Volumes/foo//dev/*'.-path '/Volumes/foo//net/*'

Find -x '/Volumes/foo/' 
    \( -path '/Volumes/foo//dev/*' 
    -o -path '/Volumes/foo//net/*' 
    -o -path '/Volumes/foo//system/*' \) -prune
-o -type f -print

답변2

나는 순수한 Perl 솔루션으로 대답하고 있습니다.

이 샌드박스를 사용하면 다음과 같습니다.

$ tree -F Volumes/ 
Volumes/ 
└── My\ HD/
    ├── Users/
    │   └── Jim/
    │       └── dev/
    │           └── github/
    │               └── twonky/
    │                   └── i_there.txt
    ├── dev/
    ├── net/
    ├── start.bat
    └── system/
        └── hello

9 directories, 3 files

다음 Perl 코드는 다음을 사용합니다 File::Find.

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use File::Find;

my $start = 'Volumes/My HD';
my $start_dev = (stat($start))[0];
my @exclude = qw/net dev system/;
my %skipdir;

sub wanted {
    my $name = $_;
    return if (stat($name))[0] != $start_dev;
    $skipdir{$File::Find::name} = 1 if $File::Find::dir eq $start && grep { $name eq $_ } @exclude;
    if (exists($skipdir{$File::Find::dir})) {
        $skipdir{$File::Find::name} = 1 if -d $name;
        return;
    }
    return if ! -f $name;
    say "Got: $File::Find::name";

}

my %args = (
    wanted => \&wanted,
    follow => 1,
    follow_skip => 1,
);


find(\%args, $start);

예상되는 결과를 제공합니다(올바르게 이해한 경우).

Got: Volumes/My HD/start.bat
Got: Volumes/My HD/Users/Jim/dev/github/twonky/i_there.txt

POC이며 향상될 수 있습니다.

또한 find2perl동일한 조건을 사용하여 find특정 호출을 연관된 Perl 코드로 변환할 수 있는 것으로 문서화된 도구 가 있다는 점에 유의하십시오.File::Find

이제 Path::Class코드가 더 간단하고 읽기 쉬워 보일 수 있습니다(동일한 결과에 대해).

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Path::Class;

my $start = Path::Class::Dir->new('Volumes/My HD');
my @exclude = qw/net dev system/;

$start->recurse(callback => sub {
    my $node = shift;
    if ($node->is_dir) {
        return $node->PRUNE if $node->parent eq $start && grep { $node->dir_list(-1) eq $_ } @exclude;
        return;
    }
    return $node->PRUNE if $node->stat()->dev != $start->stat()->dev;
    say 'Got: ', $node->stringify();
}, preorder => 1)

답변3

여러분의 도움으로 '찾기'를 안정시킬 수 있었습니다. 그러나 OS X 10.5에서 10.10으로 코드 이동또 망쳤어. 마지막 기회. "찾기"는 너무 느리고 문서화도 잘 안 되어 있으며 일관성도 없습니다. 그리고 피트를 위한 핵심 유닉스 기능입니다! 이것. 이래서 나는 남의 코드를 싫어한다. File::Find 학습에 몰두하기 시작하면서 '나는 무엇일까?행위? 내가 직접 코딩할 수 있다20분 후.”

나는 단지 그것을 했다.

sub iterate {
  my ($mydir, $ref_FH, $homevol, $ref_excludes) = @_;  # last is ref to hash

  return if (defined ($ref_excludes -> {$mydir}));   # No excludes

  my $thisvol = (stat($mydir))[0];    # What's my volume?
  return if ($thisvol != $homevol) ;  # No crossing volumes

  opendir (my $DIR, $mydir);
  while (defined (my $file = readdir($DIR))) {
    next if ($file eq '.' or $file eq '..');
    my $full = "$mydir/$file";   

    if (-l $full) {                                   # symlink
                                                         # nope
    } elsif (-f $full) {                              # file
      print {$$ref_FH} "$full\n";                        # print it
    } elsif (-d $full) {                              # dir
      &iterate($full, $ref_FH, $homevol, $ref_excludes); # iterate
    }
  }
}

그리고 그것은 빠릅니다. 그리고 가볍습니다. 이 코드는 "find's" 인수 목록 형식을 지정하는 코드 크기의 절반입니다(그리고 유지 관리가 훨씬 쉽습니다)!

관련 정보