如何在BASH中使用进程替换字符串?

时间:2018-12-18 20:11:02

标签: bash process-substitution

我知道我可以做类似的事情

cat <(cat somefile)

但是我想建立一个<()的字符串。 所以:

for file in *.file; do
    mySubs="${mySubs} <(cat ${file})"
done

cat ${mySubs} #cat <(cat 1.file) <(cat 2.file) ... <(cat something.file)

无需使用eval

2 个答案:

答案 0 :(得分:2)

直接使用命名管道。使用mktemp为每个管道创建临时文件名,以便在完成操作后将其删除。

fifos=()
for f in file1 file2 file3; do
    t=$(mktemp)
    mkfifo "$t"
    pipes+=("$t")
    someCommand "$f" > "$t" &
done

someOtherCommand "${pipes[@]}"
rm "${pipes[@]}"

答案 1 :(得分:1)

我假设cat是更复杂命令的替代者。在这里,我明确地包装它以显示:

#!/usr/bin/env bash

someCommand() { echo "Starting file $1"; cat "$1"; echo "Ending file $1"; }

wrap_all() {

  ## STAGE 1: Assemble the actual command we want to run
  local fd cmd_len retval
  local -a cmd fds fd_args
  cmd_len=$1; shift
  while (( cmd_len > 0 )); do
    cmd+=( "$1" )
    cmd_len=$((cmd_len - 1))
    shift
  done

  ## STAGE 2: Open an instance of someCommand for each remaining argument
  local fd; local -a fds
  fds=( )
  for arg; do
    exec {fd}< <(someCommand "$arg")
    fds+=( "$fd" )
    fd_args+=( "/dev/fd/$fd" )
  done

  ## STAGE 3: Actually run the command
  "${cmd[@]}" "${fd_args[@]}"; retval=$?

  ## STAGE 4: Close all the file descriptors
  for fd in "${fds[@]}"; do
    exec {fd}>&-
  done

  return "$retval"
}

调用方式:

echo "one" >one.txt; echo "two" >two.txt
wrap_all 1 cat one.txt two.txt

...输出:

Starting file one.txt
one
Ending file one.txt
Starting file two.txt
two
Ending file two.txt

请注意,这需要bash 4.1来支持自动FD分配(让我们避免使用命名管道)。