Bash进程替换和退出代码

时间:2011-09-28 16:40:26

标签: bash

我想转向以下内容:

git status --short && (git status --short | xargs -Istr test -z str)

它得到了我想要的结果,即将输出镜像到stdout并对结果进行零长度检查,使其更接近:

git status --short | tee >(xargs -Istr test -z str)

不幸地返回了tee的退出代码(总是为零)。

有没有办法优雅地获得替代流程的退出代码?

[编辑]

我现在要使用以下内容,它会阻止运行相同的命令两次,但似乎要求更好的东西:

OUT=$(git status --short) && echo "${OUT}" && test -z "${OUT}"

3 个答案:

答案 0 :(得分:5)

看这里:

  $ echo xxx | tee >(xargs test -n); echo $?
xxx
0
  $ echo xxx | tee >(xargs test -z); echo $?
xxx
0

看看这里:

  $echo xxx | tee >(xargs test -z; echo  "${PIPESTATUS[*]}")
xxx
123
  $echo xxx | tee >(xargs test -n; echo  "${PIPESTATUS[*]}")
xxx
0

那是吗?

另见Pipe status after command substitution

答案 1 :(得分:2)

我已经在这方面工作了一段时间,似乎没有办法用流程替换来做到这一点,除了求助于内联信令,并且它真的只能用于输入管道,所以我'我不打算扩大它。

但是,bash-4.0提供了coprocesses,可用于替换此上下文中的进程替换并提供清晰的收获。

您提供的以下代码段:

git status --short | tee >(xargs -Istr test -z str)

可以被类似的东西取代:

coproc GIT_XARGS { xargs -Istr test -z str; }
{ git status --short | tee; } >&${GIT_XARGS[1]}
exec {GIT_XARGS[1]}>&-
wait ${GIT_XARGS_PID}

现在,有一些解释:

coproc调用创建一个新的协同进程,命名为GIT_XARGS(您可以使用任何您喜欢的名称),并在大括号中运行该命令。为协同进程创建了一对管道,重定向其stdin和stdout。

coproc调用设置了两个变量:

  1. ${GIT_XARGS[@]}包含管道以正确处理'stdin和stdout([0]从stdout读取,[1]写入stdin),
  2. ${GIT_XARGS_PID}包含协处理'PID。
  3. 然后,运行您的命令并将其输出定向到第二个管道(即coprocess'stendin)。隐秘的>&${GIT_XARGS[1]}部分扩展为>&60,这是常规的输出到fd重定向。

    请注意,我需要将你的命令放在大括号中。这是因为管道导致子进程生成,并且它们不从父进程继承文件描述符。换句话说,以下内容:

    git status --short | tee >&${GIT_XARGS[1]}
    

    将因无效的文件描述符错误而失败,因为相关的fd存在于父进程中而不是生成的tee进程中。将它放在大括号中会导致bash将重定向应用到整个管道。

    exec调用用于关闭管道到您的协同进程。当您使用进程替换时,该进程作为输出重定向的一部分生成,并且在重定向不再生效后立即关闭它的管道。由于协同进程'管道的生命周期超出了单个重定向,我们需要明确地关闭它。

    关闭输出管道应该使进程在stdin上获得EOF条件并正常终止。我们使用wait等待终止并收获它。 wait返回协同进程的退出状态。

    最后请注意,在这种情况下,您不能使用kill来终止协同进程,因为这会改变其退出状态。

答案 2 :(得分:0)

#!/bin/bash
if read q < <(git status -s)
then
  echo $q
  exit
fi