時間をかけて質問のスクリプトをコピーして貼り付け、スクリプトと自分の回答を比較してください。ここにいくつかの興味深い結果があります:
その点に注意してください:
git pull
プレフィックスを付けて無効にしましたecho
- 色物も外しました
.ignore
ソリューションのファイル テストも削除しましたbash
。
- そして、あちこちの不要なものを取り除きました
> /dev/null
。
pwd
両方で呼び出しを削除しました。
- 例
-prune
に明らかに欠けている追加find
find
この例では、「for」の代わりに「while」を使用しましたが、これも非生産的でした
- 要点に到達するために、2 番目の例をかなり解きほぐしました。
bash
サイクルを回避し、検索ソリューションとして動作するために、シンボリック リンクをたどらないようにソリューションにテストを追加しました。
- ソリューションの機能と一致するように、ドット付きディレクトリ名に展開
shopt
できるようにするために追加されました。*
find
したがって、検索ベースのソリューションを比較しています。
#!/bin/bash
find . -name .git -type d -prune | while read d; do
cd $d/..
echo "$PWD >" git pull
cd $OLDPWD
done
bash シェル ビルド ソリューションを使用する場合:
#!/bin/bash
shopt -s dotglob
update() {
for d in "$@"; do
test -d "$d" -a \! -L "$d" || continue
cd "$d"
if [ -d ".git" ]; then
echo "$PWD >" git pull
else
update *
fi
cd ..
done
}
update *
注: ビルトイン (function
およびfor
) は、プロセスを起動するための MAX_ARGS OS 制限の影響を受けません。そのため*
、非常に大きなディレクトリでも壊れません。
ソリューション間の技術的な違い:
検索ベースのソリューションでは、C 関数を使用してリポジトリをクロールします。
- コマンドの新しいプロセスをロードする必要があります
find
。
- 「.git」コンテンツを回避しますが、git リポジトリの workdir をクロールし、それらの中でいくつかの時間を失います (最終的には、より多くの一致する要素を見つけます)。
chdir
一致ごとにいくつかの深さのサブディレクトリを通過して戻る必要があります。
chdir
find コマンドで 1 回、bash 部分で 1 回実行する必要があります。
bash ベースのソリューションでは、ビルトイン (C に近い実装ですが、解釈されます) を使用してリポジトリをクロールします。次の点に注意してください。
- 1 つのプロセスのみを使用します。
- git workdir サブディレクトリを回避します。
chdir
一度に 1 つのレベルのみを実行します。
chdir
コマンドを検索して実行するために一度だけ実行されます。
ソリューション間の実際の速度の結果:
スクリプトを起動した git リポジトリの作業中の開発コレクションがあります。
- 解決策を見つける: ~0.080 秒 (bash chdir には ~0.010 秒かかります)
- bash ソリューション: ~0.017 秒
私は、bash ビルトインによるそのような勝利を見る準備ができていなかったことを認めなければなりません。何が起こっているのかを分析した後、それはより明白になり、正常になりました。怪我に侮辱を加えるために、シェルを から/bin/bash
に変更すると/bin/sh
(行をコメントアウトし、shopt
ドット付きディレクトリを解析しないように準備する必要があります)、 ~0.008s に落ちます。それを打ちます!
次を使用して、find ソリューションをより賢く使用できることに注意してください。
find . -type d \( -exec /usr/bin/test -d "{}/.git" -a "{}" != "." \; -print -prune \
-o -name .git -prune \)
これにより、見つかった git リポジトリ内のすべてのサブリポジトリのクロールが効果的に削除されますが、クロールされたディレクトリごとにプロセスが生成されます。最終的な find ソリューションは約 0.030 秒で、以前の find バージョンよりも 2 倍以上高速ですが、bash ソリューションよりも 2 倍遅いままです。
時間がかかる/usr/bin/test
検索を避けることが重要であることに注意してください。メインリポジトリ自体がgitサブリポジトリであったため、必要でした。$PATH
-o -name .git -prune
-a "{}" != "."
結論として、bash ビルトイン ソリューションは、私にはコーナー ケースが多すぎるため使用しません (そして、最初のテストで制限の 1 つにヒットしました)。しかし、場合によっては(はるかに)高速になる理由を説明することは重要でしたが、find
ソリューションははるかに堅牢で一貫しているように思えます。