我如何遍历我的 pushd 堆栈?

How can I loop over my pushd stack?

我的动机是我正在使用多个 git 存储库,我想 运行 git status 对所有存储库进行检查,看看是什么。

因为我经常在存储库之间切换,所以我将它们放在 pushd 堆栈中,dirs -v 显示为:

0  /d/dev/helperscripts
1  /d/dev/mainsite
2  /d/dev/satellitesite
3  /d/dev/apithing

我试过使用 xargs 循环遍历它们,如下所示:

dirs | xargs -n 1 -I % bash -c 'cd -- "%" && git status '

但是,这会产生以下错误:

bash: line 0: cd: /d/dev/helperscripts /d/dev/mainsite /d/dev/satellitesite /d/dev/apithing: No such file or directory

我发现这令人惊讶,因为以下结果是按预期换行的目录列表:

dirs | xargs -n 1 echo

dirs 命令打印堆栈上由 space 分隔的目录列表,但是当使用 xargs-I 选项 xargs 期望输入由换行符分隔。使用 -p 选项到 dirs 到 return 堆栈,每行一个目录,这将给 xargs 什么想要。

此外,Bash 通常会将您的主目录替换为 dirs 列表中的 ~。这可能会导致您的命令失败,因为替换将目录括在引号中,并且 ~ 在引用时失去其特殊含义。使用 dirs-l 选项强制它总是 return 完整的、未缩写的路径。

dirs -p -l | xargs -n 1 -I % bash -c 'cd -- "%" && git status '

编辑:

我最初的解决方案旨在回答为什么 xargsdirs 的输出阻塞的主要问题。然而,正如 Ole Tange 在评论中正确指出的那样,它仍然无法正确处理包含 space 或其他 shell 元字符的目录名称。这正是 xargs -0 旨在解决的问题,但是 Bash 没有提供方便的方式来显示使用 NULL 作为分隔符的目录堆栈。

一种替代方法是遍历 $DIRSTACK 数组,其中包含与 dirs 将生成的列表相同的列表:

function dirs_git_status
{
    for d in "${DIRSTACK[@]}"
    do
        git --git-dir="${d}/.git" --work-tree="$d" status
    done
}

"${DIRSTACK[@]}" 表示法确保每个完整的数组元素都被复制到 $d 中,只要 $d 在循环中的双引号内使用,元字符就应该是保留并按原样传递给 git 而不是由 Bash.

评估

如果您使用 GNU Parallel,这也可以工作:

mkdir ~/tmp
cd ~/tmp
# Make some crazy dirs
mkdir -- -a'" "'"' '"b '<#&|()$@!!'
pushd -- -a*b
pushd ..
pushd '<#&|()$@!!'
pushd ../..

dirs -p | parallel cd -- '{= s/^~/$ENV{HOME}/ =}' '&&' pwd
dirs -p -l | parallel cd -- {} '&&' pwd