shell 重定向的一处妙用

2011-10-18 19:41

shell 重定向的一处妙用

by 王 聪

at 2011-10-18 11:41:30

original http://wangcong.org/blog/archives/1780

偶然在 dracut 的代码中发现一个使用重定向很巧妙的地方。见 modules.d/90kernel-modules/module-setup.sh 文件。

之前的老代码是这样的:

PLAIN TEXT
BASH:
  1. ##
  2.              local _f
  3.              while read _f; do case "$_f" in
  4.                  *.ko)    [[ $(<        $_f) =~ $_blockfuncs ]] && echo "$_f" ;;
  5.                  *.ko.gz) [[ $(gzip -dc <$_f) =~ $_blockfuncs ]] && echo "$_f" ;;
  6.                  esac
  7.              done

意思很清楚吧?就是在内核模块(注意是二进制格式)中匹配一些函数(字符串)。这样会很慢,因为 bash 要在庞大的二进制文件流中匹配一些指定字符串。

于是,就有人想了一个方法加速这个处理过程,把原来的单个数据流分成两个并行的数据流,同时进行匹配!很巧妙!

PLAIN TEXT
BASH:
  1. ##
  2.              function bmf1() {
  3.                  local _f
  4.                  while read _f; do case "$_f" in
  5.                      *.ko)    [[ $(<        $_f) =~ $_blockfuncs ]] && echo "$_f" ;;
  6.                      *.ko.gz) [[ $(gzip -dc <$_f) =~ $_blockfuncs ]] && echo "$_f" ;;
  7.                      esac
  8.                  done
  9.              }
  10.              # Use two parallel streams to filter alternating modules.
  11.              local merge side2
  12.              ( ( local _f1 _f2
  13.                  while  read _f1; do   echo "$_f1"
  14.                      if read _f2; then echo "$_f2" 1>&${side2}; fi
  15.                  done \
  16.                  | bmf1     1>&${merge}    ) {side2}>&1 \
  17.                  | bmf1  )      {merge}>&1

经过 refactor 之后的或许更好理解一些:

PLAIN TEXT
BASH:
  1. # subfunctions inherit following FDs
  2.             local _merge=8 _side2=9
  3.             function bmf1() {
  4.                 local _f
  5.                 while read _f; do case "$_f" in
  6.                     *.ko)    [[ $(<        $_f) =~ $_blockfuncs ]] && echo "$_f" ;;
  7.                     *.ko.gz) [[ $(gzip -dc <$_f) =~ $_blockfuncs ]] && echo "$_f" ;;
  8.                     esac
  9.                 done
  10.             }
  11.             function rotor() {
  12.                 local _f1 _f2
  13.                 while read _f1; do
  14.                     echo "$_f1"
  15.                     if read _f2; then
  16.                         echo "$_f2" 1>&${_side2}
  17.                     fi
  18.                 done | bmf1 1>&${_merge}
  19.             }
  20.             # Use two parallel streams to filter alternating modules.
  21.             eval "( ( rotor ) ${_side2}>&1 | bmf1 ) ${_merge}>&1"