コンピュータ上のすべての空の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ディレクトリが多い場合はかなりのオーバーヘッドを追加できます。

関連情報