.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ディレクトリが多い場合はかなりのオーバーヘッドを追加できます。