Need help with bash-fun?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

ssledz
246 Stars 15 Forks MIT License 62 Commits 1 Opened issues

Description

Functional programming in bash

Services available

!
?

Need anything else?

Contributors list

# 375,812
Shell
functio...
Bash
28 commits
# 361,286
Shell
functio...
Bash
C
11 commits

Introduction

Introduction to fun.sh library

Quick start

#!/bin/bash
.  fun.sh; cat fun.sh)

seq 1 4 | sum

Functions overview

||||||| |------|------|------|------|------|------| |append|buff|call|catch|curry|div| |drop|dropw|factorial|filter|foldl|foldr| |isint|isempty|isfile|isnonzerofile|isreadable|iswritable| |isdir|join|lambda|last|lhead|list| |ltail|lzip|map|maybe|maybemap|maybevalue| |mod|mul|not|ntup|ntupl|ntupr| |ntupx|peek|plus|prepend|product|ret| |res|revers|revers_str|scanl|splitc|strip| |stripl|stripr|sub|sum|take|try| |tup|tupl|tupr|tupx|unlist|λ| |with_trampoline|

list/unlist

$ list 1 2 3
1
2
3

$ list 1 2 3 4 5 | unlist 1 2 3 4 5

take/drop/ltail/lhead/last

$ list 1 2 3 4 | drop 2
3
4

$ list 1 2 3 4 5 | lhead 1

$ list 1 2 3 4 | ltail 2 3 4

$ list 1 2 3 4 5 | last 5

$ list 1 2 3 4 5 | take 2 1 2

join

$ list 1 2 3 4 5 | join ,
1,2,3,4,5

$ list 1 2 3 4 5 | join , [ ] [1,2,3,4,5]

map

$ seq 1 5 | map λ a . 'echo $((a + 5))'
6
7
8
9
10

$ list a b s d e | map λ a . 'echo $a$(echo $a | tr a-z A-Z)' aA bB sS dD eE

$ list 1 2 3 | map echo 1 2 3

$ list 1 2 3 | map 'echo $ is a number' 1 is a number 2 is a number 3 is a number

$ list 1 2 3 4 | map 'echo ($,$) is a point' (1,1) is a point (2,2) is a point (3,3) is a point (4,4) is a point

flat map

$ seq 2 3 | map λ a . 'seq 1 $a' | join , [ ]
[1,2,1,2,3]

$ list a b c | map λ a . 'echo $a; echo $a | tr a-z A-z' | join , [ ] [a,A,b,B,c,C]

filter

$ seq 1 10 | filter λ a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false'
2
4
6
8
10

foldl/foldr

$ list a b c d | foldl λ acc el . 'echo -n $acc-$el'
a-b-c-d

$ list '' a b c d | foldr λ acc el .
'if [[ ! -z $acc ]]; then echo -n $acc-$el; else echo -n $el; fi' d-c-b-a

$ seq 1 4 | foldl λ acc el . 'echo $(($acc + $el))'
10
$ seq 1 4 | foldl λ acc el . 'echo $(mul $(($acc + 1)) $el)'
64 # 1 + (1 + 1) * 2 + (4 + 1) * 3 + (15 + 1) * 4 = 64

$ seq 1 4 | foldr λ acc el . 'echo $(mul $(($acc + 1)) $el)' 56 # 1 + (1 + 1) * 4 + (8 + 1) * 3 + (27 + 1) * 2 = 56

tup/tupx/tupl/tupr

$ tup a 1
(a,1)

$ tup 'foo bar' 1 'one' 2 (foo bar,1,one,2)

$ tup , 1 3 (u002c,1,3)

$ tupl $(tup a 1)
a

$ tupr $(tup a 1) 1

$ tup , 1 3 | tupl ,

$ tup 'foo bar' 1 'one' 2 | tupl foo bar

$ tup 'foo bar' 1 'one' 2 | tupr 2

$ tup 'foo bar' 1 'one' 2 | tupx 2
1

$ tup 'foo bar' 1 'one' 2 | tupx 1,3 foo bar one

$ tup 'foo bar' 1 'one' 2 | tupx 2-4 1 one 2

ntup/ntupx/ntupl/ntupr

$ ntup tuples that $(ntup safely nest)
(dHVwbGVzCg==,dGhhdAo=,KGMyRm1aV3g1Q2c9PSxibVZ6ZEFvPSkK)

echo '(dHVwbGVzCg==,dGhhdAo=,KGMyRm1aV3g1Q2c9PSxibVZ6ZEFvPSkK)' | ntupx 3 | ntupr nest

$ ntup 'foo,bar' 1 one 1 (Zm9vLGJhcgo=,MQo=,b25lCg==,MQo=)

$ echo '(Zm9vLGJhcgo=,MQo=,b25lCg==,MQo=)' | ntupx 1 foo,bar

$ ntupl $(ntup 'foo bar' 1 one 2)
foo bar

$ ntupr $(ntup 'foo bar' 1 one 2) 2

buff

$ seq 1 10 | buff λ a b . 'echo $(($a + $b))'
3
7
11
15
19

$ seq 1 10 | buff λ a b c d e . 'echo $(($a + $b + $c + $d + $e))' 15 40

lzip

$ list a b c d e f | lzip $(seq 1 10)
(a,1)
(b,2)
(c,3)
(d,4)
(e,5)
(f,6)
$ list a b c d e f | lzip $(seq 1 10) | last | tupr
6

curry

add2() {
    echo $(($1 + $2))
}
$ curry inc add2 1
$ inc 2
3

$ seq 1 3 | map λ a . 'inc $a' 2 3 4

peek

$ list 1 2 3 \
    | peek lambda a . echo 'dbg a : $a' \
    | map lambda a . 'mul $a 2' \
    | peek lambda a . echo 'dbg b : $a' \
    | sum

dbg a : 1 dbg a : 2 dbg a : 3 dbg b : 2 dbg b : 4 dbg b : 6 12

$ a=$(seq 1 4 | peek lambda a . echo 'dbg: $a' | sum)

dbg: 1 dbg: 2 dbg: 3 dbg: 4

$ echo $a

10

maybe/maybemap/maybevalue

$ list Hello | maybe
(Just,Hello)

$ list " " | maybe (Nothing)

$ list Hello | maybe | maybemap λ a . 'tr oH Oh <<

not/isint/isempty

$ isint 42
true

$ list blah | isint false

$ not true false

$ not isint 777 false

$ list 1 2 "" c d 6 | filter λ a . 'isint $a' 1 2 6

$ list 1 2 "" c d 6 | filter λ a . 'not isempty $a' 1 2 c d 6

isfile/isnonzerofile/isreadable/iswritable/isdir

$ touch /tmp/foo

$ isfile /tmp/foo true

$ not iswritable / true

$ files="/etc/passwd /etc/sudoers /tmp /tmp/foo /no_such_file"

$ list $files | filter λ a . 'isfile $a' /etc/passwd /etc/sudoers /tmp/foo

$ list $files | filter λ a . 'isdir $a' /tmp

$ list $files | filter λ a . 'isreadable $a' /etc/passwd /tmp /tmp/foo

$ list $files | filter λ a . 'iswritable $a' /tmp /tmp/foo

$ list $files | filter λ a . 'isnonzerofile $a' /etc/passwd /etc/sudoers /tmp

$ list $files | filter λ a . 'not isfile $a' /tmp /no_such_file

try/catch

$ echo 'expr 2 / 0' | try λ _ . 'echo 0'
0

$ echo 'expr 2 / 0' | try λ status . 'echo $status' 2

$ echo 'expr 2 / 2' | try λ _ . 'echo 0' 1

try λ  _ . 'echo some errors during pull; exit 1' < 
$ echo 'expr 2 / 0' 
| LANG=en catch λ cmd status val . 'echo cmd=$cmd,status=$status,val=$val' cmd=expr 2 / 0,status=2,val=(expr:,division,by,zero)
$ echo 'expr 2 / 2' | catch λ _ _ val . 'tupl $val'
1

scanl

$ seq 1 5 | scanl lambda acc el . 'echo $(($acc + $el))'
1
3
6
10
15
$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | last
15

with_trampoline/res/call

factorial() {
    fact_iter() {
        local product=$1
        local counter=$2
        local max_count=$3
        if [[ $counter -gt $max_count ]]; then
            res $product
        else
            call fact_iter $(echo $counter\*$product | bc) $(($counter + 1)) $max_count
        fi
    }

with_trampoline fact_iter 1 1 $1

}

$ time factorial 30 | fold -w 70
265252859812191058636308480000000

real 0m1.854s user 0m0.072s sys 0m0.368s

time factorial 60 | fold -w 70
8320987112741390144276341183223364380754172606361245952449277696409600
000000000000

real 0m3.635s user 0m0.148s sys 0m0.692s

$ time factorial 90 | fold -w 70
1485715964481761497309522733620825737885569961284688766942216863704985
393094065876545992131370884059645617234469978112000000000000000000000

real 0m4.371s user 0m0.108s sys 0m0.436s

Examples

processNames() {

uppercase() { local str=$1 echo $(tr 'a-z' 'A-Z' <<< ${str:0:1})${str:1} }

list [email protected]
| filter λ name . '[[ ${#name} -gt 1 ]] && ret true || ret false'
| map λ name . 'uppercase $name'
| foldl λ acc el . 'echo $acc,$el'

}

processNames adam monika s slawek d daniel Bartek j k

Adam,Monika,Slawek,Daniel,Bartek

Running tests

cd test
./test_runner

Contribution guidelines

Feel free to ask questions in chat, open issues, or contribute by creating pull requests.

In order to create a pull request * checkout master branch * introduce your changes & bump version * submit pull request

Resources

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.