![Unix는 여러 가지 자두와 유형 fs에 압도됩니까?](https://linux55.com/image/155116/Unix%EB%8A%94%20%EC%97%AC%EB%9F%AC%20%EA%B0%80%EC%A7%80%20%EC%9E%90%EB%91%90%EC%99%80%20%EC%9C%A0%ED%98%95%20fs%EC%97%90%20%EC%95%95%EB%8F%84%EB%90%A9%EB%8B%88%EA%B9%8C%3F.png)
나는 이 루빅스 큐브 작업에 며칠을 보냈습니다. 한 문제를 해결하기 위해 내가 하는 모든 일은 다른 문제를 파괴합니다.
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" 인수 목록 형식을 지정하는 코드 크기의 절반입니다(그리고 유지 관리가 훨씬 쉽습니다)!