前回はパイプを使ったのですが、結局ラムダが使えないので中途半端なんですよね。takewhileやfilterを汎用の関数にできないのです。
しかし、evalを使うとラムダっぽいことができます。
a=1 b=c eval $b=\$a echo $c # 1
evalは、c=$aという文字列をコマンド化しています。右辺の$はエスケープしないとここで$aが変数展開されてしまいます。
これと同様に、ラムダを文字列として変数に代入してevalでコマンド化します。
lambda="test \$x -gt 1" x=2 if echo $lambda; then echo $x fi
test $x -gt 1が評価されて、0が返って、echo $xが実行されます。
これでtakewhileが書けます。
#!/bin/sh # takewhile.sh lambda=$1 shift while [ $# -gt 0 ]; do lambda="$lambda $1" shift done while read x do if eval $lambda; then echo $x else exit fi done
前段は、引数がwhite spaceで区切られて渡されてくるので、それを連結しています。
filterも同様に書けます。
#!/bin/sh # filter.sh lambda=$1 shift while [ $# -gt 0 ]; do lambda="$lambda $1" shift done while read x do if eval $lambda; then echo $x fi done
これらをパイプでつないで、
#!/bin/sh fibs() { local m=1 local n=1 while :; do echo $n local tmp=$n n=$((n+m)) m=$tmp done } fibs | ./takewhile.sh test \$x -le $1 | ./filter.sh test \$\(\(\$x%2\)\) -eq 0 | ./sum.sh
しかし、ここまでやる必要があるのでしょうか。速度も不安です。