컴퓨터의 모든 빈 Git 저장소를 찾는 스크립트

컴퓨터의 모든 빈 Git 저장소를 찾는 스크립트

.git우리는 빈 git 저장소에는 디렉토리만 포함되어 있다는 것을 알고 있습니다.

컴퓨터에서 빈 git 저장소를 모두 찾고 싶습니다.

나는 이 과정에 대해 다음과 같이 생각했습니다.

  1. 지정된 모든 디렉토리 찾기.git
  2. 내부에 있는 경우 제외합니다.Trash
  3. 다른 저장소가 귀하의 저장소가 아닌 경우 제외하십시오(일부 타사 응용 프로그램도 git 저장소를 가져옵니다).
  4. 루프를 반복하다
  5. 각 저장소의 상위 디렉터리에 대해 최상위 파일 및 폴더 수를 계산합니다.
  6. 개수가 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서브루틴은 wantedPerl의 내장 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

이제 스크립트를 실행 가능하게 만들고 실행해 보세요. 다음 디렉터리의 이름을 인쇄합니다.

  1. Trash, Temp 또는 opt 디렉토리의 하위 디렉토리가 아닙니다.
  2. .git 하위 디렉터리를 포함하고
  3. 다른 파일이 포함되어 있지 않습니다.

그것이 바로 ./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 디렉토리가 많은 경우 상당한 오버헤드를 추가할 수 있습니다.

관련 정보