Bash

Bash 腳本循環連接基於名稱變數的管道/重定向

  • March 27, 2020

我有一個命令會產生許多輸出行,我稍後會用 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

最簡單的方法是遞歸地一次做一個:

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"
}

你可以這樣做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腳本的每一行,花點時間考慮一下。

引用自:https://unix.stackexchange.com/questions/575322