我如何遍历我的 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 '
编辑:
我最初的解决方案旨在回答为什么 xargs 被 dirs 的输出阻塞的主要问题。然而,正如 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
我的动机是我正在使用多个 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 '
编辑:
我最初的解决方案旨在回答为什么 xargs 被 dirs 的输出阻塞的主要问题。然而,正如 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