生成任意数量的进程替换作为tee参数

时间:2017-04-11 17:05:57

标签: bash

我在bash脚本中使用此代码。我用它将源文件夹传输到多个目的地:

while(!a){
   if(b.b){
      throw new Exception("b is true");
   }
   System.out.println("there is something more to execute");
}

此命令效果很好。我想在脚本的开头设置目的地。所以目的地的数量可能会有所不同。

例如,目的地可以是var或数组:

b.b

有一个很好的方法吗?

1 个答案:

答案 0 :(得分:5)

这种情况eval是更容易的选择之一,但需要非常谨慎地使用它。

unpackInDestinations() {
  local dest currArg='' evalStr=''
  for dest; do
    printf -v currArg '>(cd %q && exec tar xf -)' "$dest"
    evalStr+=" $currArg"
  done
  eval "tee $evalStr >/dev/null"
}

tar cf - SOURCE/ | unpackInDestinations /Volumes/dest{1,2}

效率较低(但也许没有,导致任何人试图审计代码的安全性同样令人惊愕),也可以写一个递归函数:

unpackInDestinations() {
  local dest
  if (( $# == 0 )); then
    cat >/dev/null
  elif (( $# == 1 )); then
    cd "$1" && tar xf -
  else
    dest=$1; shift
    tee >(cd "$dest" && exec tar xf -) | unpackInDestinations "$@"
  fi
}

此创建的tee的数量因参数的数量而异,因此它的效率远低于手写代码或基于eval的等效值。

如果你只需要支持新版本的bash(下面要求至少 4.1),那么还有一些额外的魔法可以提供两全其美的效果:

unpackInDestinations() {
  local -a dest_fds=( ) args=( )
  local arg fd_num retval

  # open a file descriptor for each argument
  for arg; do
    exec {fd_num}> >(cd "$arg" && exec tar xf -)
    dest_fds+=( "$fd_num" )
    args+=( "/dev/fd/$fd_num" )
  done

  tee "${args[@]}" >/dev/null; retval=$?

  # close the FDs
  for fd_num in "${dest_fds[@]}"; do
    exec {fd_num}>&-
  done

  # and return the exit status we got from tee
  return "$retval"
}