Bash 脚本循环根据名称变量连接管道/重定向

Bash 脚本循环根据名称变量连接管道/重定向

我有一个命令可以生成许多输出行,稍后我将 grep 搜索这些输出行。

根据过去的答案,我知道我可以使用一个长命令并同时执行所有过滤器:

https://superuser.com/questions/7448/can-the-output-of-one-command-be-piped-to-two-other-commands

command | tee >(grep filter1 >./filter1) >(grep filter2 >./filter2)

现在,如果我可以根据过滤器参数创建一个结构,然后将其解耦到那个长命令中,那么我就可以编写一个脚本来为我完成繁重的工作,就像下面的 shell 伪代码一样:

filters='filter1 filter2 filter3'
for filter in $filters; do
  SOMEHOW_STORE_REDIRECTIONS+=>(grep $filter > ./${filter})
command | tee >{SOMEHOW_DECOUPLE_STORE_REDIRECTIONS_VAR_INTO_LONG_COMMAND} | cat > /dev/null

答案1

最简单的方法是递归地一次执行一个:

filter() {
  if [ "$#" -eq 0 ]
  then
    cat
  else
    f="$1"
    shift
    tee >(grep "$f" > "$f") | filter "$@"
  fi
}

printf '%s\n' {foo,bar}{0..100} | filter foo bar r3

但是,这会增加许多额外的缓冲区和步骤,因此您也可以谨慎使用eval.这是可以的,因为文件名被小心地转义了:

filter() {
   cmd="tee "
   for f in "$@"
   do
     cmd+=">(grep -e ${f@Q} > ${f@Q}) "
   done
   eval "$cmd"
}

答案2

你可以这样做eval

# usage xfilter filter_spec filter_args...
xfilter() {
    local cmd flt=$1; shift
    printf -v cmd " >($flt)" "$@"
    eval "tee $cmd"
    wait
}

$ echo paa | xfilter 'sed %q' s/a/e/g s/a/o/g
paa
pee
poo

$ tgrep(){ grep "$1" > "./$1"; }
$ printf '%s\n' foo bar | xfilter 'tgrep %q' foo bar
foo
bar
$ grep . foo bar
foo:foo
bar:bar

不,还有完全没问题eval如果明智地使用。毕竟,bash 会eval分别调用脚本的每一行,请花点时间考虑一下。

相关内容