shell 重定向的一处妙用

偶然在 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"

你可能感兴趣的:(programming)