.git
우리는 빈 git 저장소에는 디렉토리만 포함되어 있다는 것을 알고 있습니다.
컴퓨터에서 빈 git 저장소를 모두 찾고 싶습니다.
나는 이 과정에 대해 다음과 같이 생각했습니다.
- 지정된 모든 디렉토리 찾기
.git
- 내부에 있는 경우 제외합니다.
Trash
- 다른 저장소가 귀하의 저장소가 아닌 경우 제외하십시오(일부 타사 응용 프로그램도 git 저장소를 가져옵니다).
- 루프를 반복하다
- 각 저장소의 상위 디렉터리에 대해 최상위 파일 및 폴더 수를 계산합니다.
- 개수가 0(제외
.git
) 또는 1(포함.git
)이면 저장소가 비어 있습니다.echo
그것.
이것은 내 스크립트입니다.
find / -type d -name .git 2>/dev/null |
{
while read gitFolder; do
if [[ $gitFolder == *"/Temp/"* ]]; then
continue;
fi
if [[ $gitFolder == *"/Trash/"* ]]; then
continue;
fi
if [[ $gitFolder == *"/opt/"* ]]; then
continue;
fi
parent=$(dirname $gitFolder);
echo "";
if [ $(ls $parent -A | wc -l ) != 1 ]; then
echo $parent
fi
done
}
그러나 이것은 예상대로 작동하지 않았습니다. 모든 저장소가 나열됩니다. 이는 비교 섹션에 오류가 있지만 찾을 수 없음을 의미합니다. 내가 뭘 잘못했나요?
또한 이것이 최선의 접근 방식이 아닐 수도 있다고 생각합니다. 더 좋게 만드는 방법에 대한 아이디어가 있나요?
답변1
이는 비교가 작동하지 않는 이유를 설명하지 않지만 출력을 반복하지 않고 find
이 모든 작업을 직접 수행할 수 있습니다( find
지원 하는 경우).-execdir
find / -type d \( \( \( -name Temp -o -name Trash -o -name opt \) -prune \) \
-o \( -name .git -execdir sh -c '[ "$(ls -A)" = ".git" ] && pwd' \; \) \)
이는 모든 디렉토리, prunes 등을 찾습니다. Temp
따라서 하위 디렉토리도 탐색하지 않습니다. 라는 디렉터리를 찾으면 .git
상위 디렉터리에서 테스트를 실행하여 .git
해당 파일이 존재하는 유일한 파일인지 확인하고, 그렇다면 pwd
현재 디렉터리를 인쇄합니다.
답변2
$ cat find-empty-git.pl
#!/usr/bin/perl
use File::Find;
use List::Util qw(uniq);
push @ARGV, './' unless @ARGV;
@ARGV = uniq(@ARGV);
foreach (@ARGV) { die "$_ is not a directory" unless -d $_ };
find(\&wanted, @ARGV);
sub wanted {
$File::Find::prune = 1 if $File::Find::name =~ m=/(Trash|Temp|opt)($|/)=;
return unless (-d && /^\.git$/);
opendir(my $dh, '.') ||
warn "Can't open $File::Find::dir: $!" &&
return;
return if (grep { ! /^(\.{1,2}|\.git)$/ } readdir($dh));
closedir($dh);
print "$File::Find::dir\n";
}
이 Perl 스크립트는 명령줄에 지정된 디렉토리 이름을 검색할 최상위 디렉토리(또는 디렉토리)로 사용합니다.
./
디렉터리를 지정하지 않으면 기본값은 입니다. 각 매개변수가 실제로 uniq()
디렉토리 인지 확인하고목록::유틸리티중복된 디렉토리 이름을 제거하는 모듈입니다. 이것파일::찾기모듈은 지정된 디렉터리를 재귀적으로 검색하는 데 사용됩니다. 두 모듈 모두 핵심 Perl 모듈이며 Perl에 포함되어 있습니다(즉, 별도로 설치할 필요가 없습니다).
발견된 각 파일 이름에 대해 wanted
서브루틴이 실행됩니다.
/Trash
먼저, 현재 파일 이름의 전체 경로 이름이 , 또는 , 또는 이들 중 하나의 하위 항목 /Temp
으로 끝나는 지 확인합니다. /opt
그렇다면 검색 트리에서 디렉터리를 제거합니다.
다음으로, 파일 이름이 디렉터리도 아니고 가 아닌 경우 .git
서브루틴은 즉시 반환됩니다.
$dh
그렇지 않으면 파일이 포함된 디렉토리가 열리고(디렉토리 핸들이라는 변수를 사용하여. 참조 perldoc -f opendir
) 디렉토리의 내용이 검사됩니다. 어떤 이유로든(예: 권한) 읽기 위해 디렉토리를 열 수 없는 경우 이는 치명적이지 않은 오류로 처리됩니다(경고 메시지가 stderr에 인쇄되고 서브루틴이 반환됨).
grep
서브루틴은 wanted
Perl의 내장 grep 기능을 사용합니다. 이것은아니요grep 외부 명령. Perl의 grep
함수는 목록(배열)을 입력으로 받아들이고 코드 블록이 true로 평가되는 또 다른 목록을 반환합니다. 목록 컨텍스트에서 이 readdir
함수는 디렉터리의 파일 이름 목록을 반환합니다. perldoc -f grep
및 을 참조하십시오 perldoc -f readdir
.
즉, return if grep... readdir($dh)
디렉터리에 일치하거나 일치하지 않는 "파일"이 있는 경우 .
해당 ..
줄은 필요한 기능에서 일찍 반환됩니다(즉, 디렉터리 이름을 인쇄하기 전) .git
. 여기서는 "문서"라는 단어가 사용되었습니다.일반적인 의미일반 파일, 심볼릭 링크, 디렉터리, 장치 노드, 명명된 파이프, 소켓 등을 포함합니다.
마지막으로 이 시점에서 디렉터리 이름이 인쇄됩니다.
그런데, 줄 바꿈으로 구분된 대신 NUL로 구분된 디렉터리 이름 목록이 필요한 경우 print "$File::Find::dir\n";
해당 줄을 .print "$File::Find::dir\0";
샘플 실행. 먼저 테스트 환경을 만들고 .git 하위 디렉터리를 포함하는 일부 디렉터리(a, b, c)를 만듭니다. 다음 디렉터리 중 하나에 파일을 만듭니다. .git 하위 디렉터리는 없지만 .git 하위 디렉터리(e)가 있는 다른 디렉터리(d)를 만듭니다. 그리고 ./Trash/ 및 ./Temp/ 아래의 일부 .git 하위 디렉터리
$ mkdir -p {a,b,c}/.git/
$ touch a/file1
$ mkdir -p d/e/.git
$ mkdir -p Trash/f/.git Temp/g/.git
$ tree --metafirst --noreport -paf a b c d Trash Temp
[drwxr-xr-x] a
[-rw-r--r--] ├── a/file1
[drwxr-xr-x] └── a/.git
[drwxr-xr-x] b
[drwxr-xr-x] └── b/.git
[drwxr-xr-x] c
[drwxr-xr-x] └── c/.git
[drwxr-xr-x] d
[drwxr-xr-x] └── d/e
[drwxr-xr-x] └── d/e/.git
[drwxr-xr-x] Trash
[drwxr-xr-x] └── Trash/f
[drwxr-xr-x] └── Trash/f/.git
[drwxr-xr-x] Temp
[drwxr-xr-x] └── Temp/g
[drwxr-xr-x] └── Temp/g/.git
이제 스크립트를 실행 가능하게 만들고 실행해 보세요. 다음 디렉터리의 이름을 인쇄합니다.
- Trash, Temp 또는 opt 디렉토리의 하위 디렉토리가 아닙니다.
- .git 하위 디렉터리를 포함하고
- 다른 파일이 포함되어 있지 않습니다.
그것이 바로 ./b
평화입니다../c
./d/e
$ chmod +x ./find-empty-git.pl
$ ./find-empty-git.pl ./
./b
./d/e
./c
그런데, 상당히 선형적인 코드를 읽고 작업하는 것이 얼마나 편한지에 따라 find
적당히 길고 복잡한 명령줄보다 읽고 이해하기가 더 쉬울 수도 있고 그렇지 않을 수도 있습니다. 저에게는 확실히 더 쉽습니다(하지만 아마도 File::Find
지난 수십 년 동안 유사한 Little 기반 스크립트를 수십 개 작성했기 때문일 것입니다).
이것이 실행하는 것보다 빠를지 말하기는 어렵습니다 find
. 아마도. 아마도. .git 하위 디렉터리를 포함하는 디렉터리 수에 따라 다릅니다. 이 스크립트를 사용하면 perl
한 번만 실행하면 되며 외부 프로그램은 실행되지 않습니다. Stephen의 명령은 find
발견된 각 .git 디렉토리에 대해 sh
한 번 ls
(어쩌면 다시 ) 실행되어야 합니다 pwd
. 이는 .git 디렉토리가 많은 경우 상당한 오버헤드를 추가할 수 있습니다.