for
Bashループの出力をソートしようとしています。
現在のループから得られた出力は次のようになります。
Directory: /some/long/directory/path Remote: some-remote
Directory: /some/dir/path Remote: other-remote
次のように並べ替えます。
Directory: /some/long/directory/path Remote: some-remote
Directory: /some/dir/path Remote: other-remote
この出力を生成する現在の基本ループは次のとおりです。
for dir in $(find /some/path -type d -name .git); do
cd $dir
remote=$(git remote)
printf "Directory: $dir\tRemote: $remote\n
done
私は以下を試してみました。
column
(forループなので、各行の形式を個別に指定します)printf
(printf "Directory: %s Remote: %s\n" "$dir" "$remote"
)awk
(echo "Directory: $dir Remote: $remote" | awk '{printf ("%s-20s %s-20s %s-20s %s-20s",$1 $2 $3 $4)}'
)
このコマンドには他の多くのバリエーションがあります。
おそらく基本的なものが欠けているかもしれません(オンラインで他の例を見て、ページを読むことに全力を尽くしましたがman
)うまくいきません。
誰かが私が間違っていることを指摘してくれたら本当に感謝します。
答え1
column
うまくいくでしょう。ただし、すべてのループ反復に追加するわけではありませんが、最後に次のものを追加します。
for
...
done | column -t
出力:
Directory: /some/long/directory/path Remote: some-remote
Directory: /some/dir/path Remote: other-remote
スクリプトに関するいくつかの追加注意事項:
find
このように出力を繰り返さないでください。ここで確認してください。- 参照ファイル/ディレクトリ変数 - >
cd "$dir"
printf
FORMAT
文字列に変数を使用しないでください。 -->printf 'Directory: %s\tRemote: %s\n' "$dir" "$remote"
答え2
column
ただし、使用できます。
- 餌を与えなければなりません包括的な各繰り返しの代わりにループに出力します。
- あなたは避けるべきです繰り返しの出力
find
。
シェルがあることを示したので、(そして@ Kusalanandaが指摘したように)オプションを使用してシェルから直接反復するbash
ことができます。globstar
nullglob
dotglob
shopt -s globstar
shopt -s nullglob
shopt -s dotglob
for d in **/.git/
do
cd "$d"
printf "Directory: %s\tRemote: %s\n" "${d%/.git/}" "$(git remote)"
cd - >/dev/null
done | column -t -s $'\t'
- この
globstar
オプションを使用すると、**
すべての深さの中間ディレクトリに一致するglob(「ワイルドカード」とも呼ばれます)を有効にして、ループ内のディレクトリツリーに深く入ることができます。 nullglob
一致するディレクトリがない場合、このオプションを使用するとまったく繰り返されません。これがなければ、globパターンは次の内容を含むディレクトリを参照するように扱われます。リテラル名**/.git/
一致するファイル名がない場合、ループはこの(意味のない)値で一度実行されます$d
。- このオプションは、「隠された」中間ディレクトリ(例:のようにaで始まるディレクトリ)も一致することを
dotglob
確認します。**
.
some/directory/.path/repository
- パスの - 部分は不要なので、シェル文字列処理の指示は
.git/
値の${d%/.git/}
最後に現れるものを削除します。/.git/
$d
- ループ内の出力はタブで区切られているため、コマンドにデフォルト値(スペースで区切られた
column
列など-s $'\t'
)ではなく、タブを入力列区切り文字として使用するように指示します。
答え3
ループを再作成します。
find /some/path -type d -name .git -exec sh -c '
for dirpath do
printf "Directory: %s@Remote: %s\n" \
"${dirpath%/.git}" \
"$( git -C "$dirpath" remote )"
done' sh {} + |
column -s '@' -t
column
これはフォーマットされた出力に使用されますfind
。このコマンドは、一括して見つかったディレクトリパスで呼び出されるインラインスクリプトを使用して、find
すべてのディレクトリを見つけて必要な情報を出力します。出力のために、インラインスクリプトは指定されたディレクトリパスを次に変更します。.git
sh -c
いいえ最後に実際のコンテンツを含めます/.git
。つまり、Gitプロジェクトディレクトリを指します。
出力は、後でデータをソートするために使用される@
文字で表に書き込まれます。column
別の文字を使用する必要がある場合は、@
インラインsh -c
スクリプトと呼び出しを変更してください。column
関連:
Gitリポジトリがある場合多くの種類リモコンの場合、各リモコンの出力を個別にコピーする必要があります。
find /some/path -type d -name .git -exec sh -c '
for dirpath do
git -C "$dirpath" remote |
while IFS= read -r remote; do
printf "Directory: %s@Remote: %s\n" \
"${dirpath%/.git}" "$remote"
done
done' sh {} + |
column -s '@' -t
ここでは行を読みますgit -C "$dirpath" remote
。各行には、Gitリモートの名前が含まれ、各リモート読み取りに対して出力されます。
これは出力することができます
Directory: /some/path/src Remote: origin
Directory: /some/path/src Remote: private
リポジトリに/some/path/src
2つのリモコンがある場合。
楽しみにしてJSON出力が欲しいです。
find /some/path -type d -name .git -exec sh -c '
for dirpath do
git -C "$dirpath" remote |
while IFS= read -r remote; do
jo directory="${dirpath%/.git}" remote="$remote"
done
done' sh {} +
可能な出力:
{"directory":"/some/path/src","remote":"origin"}
{"directory":"/some/path/src","remote":"private"}
{"directory":"/some/path/yash-shell","remote":"origin"}
{"directory":"/some/path/zsh-shell","remote":"origin"}
{"directory":"/some/path/datamash","remote":"origin"}