![Bash 脚本循环根据名称变量连接管道/重定向](https://linux22.com/image/170002/Bash%20%E8%84%9A%E6%9C%AC%E5%BE%AA%E7%8E%AF%E6%A0%B9%E6%8D%AE%E5%90%8D%E7%A7%B0%E5%8F%98%E9%87%8F%E8%BF%9E%E6%8E%A5%E7%AE%A1%E9%81%93%2F%E9%87%8D%E5%AE%9A%E5%90%91.png)
我有一个命令可以生成许多输出行,稍后我将 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
分别调用脚本的每一行,请花点时间考虑一下。