暗无天日

=============>DarkSun的个人博客

Bash版的join,map和filter

今天看到有人用Bash实现了join,map和filer函数(可惜没有reduce函数),觉得很有趣,所以记录下来

join 函数

join() { { local indelimiter; indelimiter="${1- }" ; local outdelimiter;
           outdelimiter="${2-.}" ; }
         local car
         local cdr
         local IFS
         IFS="${indelimiter}"
         read -t 1 car cdr || return
         test "${cdr}" || { echo "${car}" ; return ; }
         echo "${car}${outdelimiter}${cdr}" | ${FUNCNAME} "${indelimiter}"
         "${outdelimiter}"
       }

map 函数

map() { { local function_name ; function_name="${1}" ; }
        local car
        local cdr
        local IFS
        IFS="${indelimiter- }"
        read -t 1 car cdr || return
        test "$( declare -f ${function_name} )" || return
        test "${car}" || { true ; return ; }
        ${function_name} ${car}
        echo "${cdr}" | ${FUNCNAME} "${function_name}"
      }

filter 函数

filter() { { local function_name ; function_name="${1}" ; }
           local car
           local cdr
           local IFS
           IFS="${indelimiter- }"
           read -t 1 car cdr || return
           test "$( declare -f ${function_name} )" || return
           test "${car}" || { true ; return ; }
           ${function_name} "${car}" || echo -n "${car} "
           echo "${cdr}" | ${FUNCNAME} "${function_name}"
}

上面定义的三个函数都遵循一个模式:

  1. 数据通过 read 读入,这样的好处是数据可以是任意长度
  2. 所有的数据都被 read 分成 car 和 cdr 两部分(一看就是玩lisp的;>)
  3. 在函数内使用 FUNCNAME 引用自身的函数名来实现递归
  4. 为了避免递归陷入死循环,需要对 carcdr 进行检查,提前退出。

参照这个模板的,我们也可以很容易定义出reduce函数

reduce() { { local function_name ; function_name="${1}" ; }
        local first
        local second
        local cdr
        local IFS
        IFS="${indelimiter- }"
        read -t 1 first second cdr || return
        test "$( declare -f ${function_name} )" || return
        test -n "${second}" || { echo ${first} ; return ; }
        first=$(${function_name} ${first} ${second})
        echo "${first}${IFS}${cdr}" | ${FUNCNAME} "${function_name}"
      }

我们来测试一把

source ~/bin/autoload/reduce.sh
sum()
{
    expr $1 \+ $2
}
echo {1..4} |reduce sum
10