シェル「for」ループで生成された出力を列でソートする方法

シェル「for」ループで生成された出力を列でソートする方法

forBashループの出力をソートしようとしています。

現在のループから得られた出力は次のようになります。

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ことができます。globstarnullglobdotglob

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すべてのディレクトリを見つけて必要な情報を出力します。出力のために、インラインスクリプトは指定されたディレクトリパスを次に変更します。.gitsh -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/src2つのリモコンがある場合。


楽しみにして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"}

関連情報