如何按列对齐 shell“for”循环中生成的输出

如何按列对齐 shell“for”循环中生成的输出

我正在尝试对齐 bashfor循环的输出。

目前,我从循环中获得的输出如下所示:

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

由于您指示您的 shell 是bash,因此您可以使用globstarand nullglob(以及,正如@Kusalananda 所指出的dotglob)选项直接从 shell 进行迭代:

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
  • dotglob选项将确保**也匹配“隐藏”中间目录(即以 a 开头的目录.,如 中some/directory/.path/repository)。
  • 由于您不需要.git/路径的 - 部分,因此 shell 字符串处理指令将从 的值中${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有两个遥控器。


只是为了好玩,我们想要 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"}

相关内容