쉘 "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/src두 개의 리모컨이 있는 경우.


재미삼아 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"}

관련 정보