BashでProject Euler(5) パイプ

前回は、フィボナッチ数列を垂れ流すだけのfibsを使いたいが、fibsが終わらないと次に進まないのでできないという話でした。
しかし、Linuxにはパイプというものがあったはずです。これならfibsがある程度進めば、その下流の関数が動き出すはずです。そこで、適当にtakewhileっぽいものを書きます。

takewhile() {
    upper=$1
    local x
    while read x; do
        if [ $x -gt $upper ]; then
            break
        fi
        echo $x
    done
}

readは標準出力から1行読んでxに格納します。$xがtakewhileの引数の$upperより大きくなればbreakで打ち切られます。
そして、

N=$1
fibs | takewhile $N

とすれば、$N以下のフィボナッチ数列を列挙されます。
偶数でフィルターする関数も同様に書きます。そして、最後の和を取る部分は汎用的なのでファイルにします。sum.shを次のように書きます。

#!/bin/bash
#sum.sh

s=0
while read x; do
    let s+=x
done
echo $s

最後にこれらをパイプでつないで、

#!/bin/bash

fibs() {
    local m=1
    local n=1
    while :; do
        echo $n
        local tmp=$n
        n=$((n+m))
        m=$tmp
    done
}

takewhile() {
    local upper=$1
    local x
    while read x; do
        if [ $x -gt $upper ]; then
            break
        fi
        echo $x
    done
}

filter_even() {
    local x
    while read x; do
        if [ $((x%2)) -eq 0 ]; then
            echo $x
        fi
    done
}

N=$1
fibs | takewhile $N | filter_even | ./sum.sh

local

関数内でlocalを使うとローカル変数になります。

#!/bin/bash

f() {
    local n=1
    let n+=1
}

n=1
f
echo $n     # 1
#!/bin/bash

f() {
    let n+=1
}

n=1
f
echo $n     # 2