从第一个命令获取输出以在Bash中退出

时间:2018-02-22 21:08:20

标签: bash parallel-processing

假设我有一个Bash脚本,它接受一个参数(即端口号),并用任一结果执行一些逻辑

  1. 挂起1秒钟,退出超时错误或
  2. 在几毫秒内成功并输出一条消息,例如" ON"或" OFF"。
  3. 找到导致结果2的参数的一种方法是在参数的可能值上运行脚本循环,但这需要N秒来查找参数。假设输出是一致的(例如,如果多个实例导致结果2,则它们的输出消息是相同的)。

    是否有办法在参数的每个可能值的同时(在合理的毫秒内)运行Bash脚本的N个实例,并从最快完成的实例获取输出消息?这将导致输出不到1秒。

1 个答案:

答案 0 :(得分:0)

要允许复制器,让我们首先创建一个与您的命令相似的功能:

try_or_wait() {
  local argument=$1  # doesn't really matter for our purposes
  if (( RANDOM % 10 == 0 )); then   # 10% return a result immediately
    if (( (RANDOM + argument) % 2 == 0 )); then
      echo ON
    else
      echo OFF
    fi
  else                              # 90% hang, and then fail
    sleep 10
    exit 1
  fi
}

......那么,我们怎么能用呢?

declare -a pids=( )
mkfifo out.fifo

# start 20 processes, passing your port number to each
for ((i=0; i<20; ++i)); do
  try_or_wait "$1" >out.fifo & pids+=( "$!" )
done

# read one result
read result <out.fifo

# kill all the remaining children
kill "${pids[@]}"

echo "Got the result: $result"

不是这是唯一的方法。让GNU xargs为您完成产生子进程的工作:

export -f try_or_wait  # export shell functions so child processes can run it

read -r result < <(
  for ((i=0; i<20; ++i)); do
    printf '%s\0' "$1"
  done | xargs -0 -n 1 -P 20 bash -c 'try_or_wait "$@"' _
)

请注意,上述内容是安全的,因为每个实例都会同时执行一次写入 - 一个echo,足够短以使整个输出适合单个系统调用。如果程序的每个实例都有足够的输出来要求多个系统调用(或输出拆分多次写入),则可能需要一个可以为您执行整理的工具。