Bash functional: Difference between revisions

From wikinotes
No edit summary
 
(20 intermediate revisions by the same user not shown)
Line 1: Line 1:
Fancy loops that let you process things incrementally in a pipeline.<br>
You'll almost never use these directly, but it might be inspiration for a more useful function.
{{ NOTE |
If your callable accepts parameter as stdin, you don't need map/filter (ex. sed/grep work just fine from stdin).<br>
you could also use xargs to pass stdin lines as callable params.
}}
= Filter =
= Filter =
<blockquote>
<blockquote>
<source lang="bash">
<syntaxhighlight lang="bash">
# filters out results not matching 'grep foo'
# Call callable/params($*), passing each each STDIN line as the last parameter
find . \
#
  | while read line; do \
# EXAMPLE:
    echo $line | grep foo && echo "$line"; \
#  divisible_by_2() { [ $(($1 % 2)) -eq 0 ] }
  done
#  echo {1..10} | tr ' ' '\n' | filter divisible_by_2
</source>
#  #> 2
#  #> 4
#  #> ...
#
filter() {
    local input
 
    while read -r input; do
        if "$@" "${input}" 2>&1 > /dev/null ;
            echo "${input}"
        fi
    done
}
</syntaxhighlight>
</blockquote><!-- Filter -->
</blockquote><!-- Filter -->


Line 13: Line 35:
<blockquote>
<blockquote>
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
# Call callable/params($*), passing each each STDIN line as the last parameter
#
# EXAMPLE:
#  print_divisible_by_2() {
#    [ $(($1 % 2)) -eq 0 ] && echo "$1:yes" || echo "$1:no"
#  }
#  echo {1..10} | tr ' ' '\n' | map print_divisible_by_2
#  #> 1:no
#  #> 2:yes
#  #> ...
#
map() {
map() {
    # ARGS:
    #  $1:    name of function to call
    #  STDIN:  the item to pass as argument to function
     local input
     local input


Line 23: Line 53:
     done
     done
}
}
</syntaxhighlight>
Example
<syntaxhighlight lang="bash">
print_if_divisible_by_2() {
    # prints number if divisible by 2
    [ $(($1 % 2)) -eq 0 ] && echo $1
}
cat << EOF | map print_if_divisible_by_2
1
2
3
4
EOF
#> 2
#> 4
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Map -->
</blockquote><!-- Map -->
Line 46: Line 58:
= Reduce =
= Reduce =
<blockquote>
<blockquote>
<syntaxhighlight lang="bash">
# callable/params must accept aggregate as 2nd-last param, and input as last param.
#
# EXAMPLE:
#  sum() { echo $(($1 + $2)) }
#  echo {1..10} | tr ' ' '\n' | reduce sum 0
#  #> 55
#
reduce() {
    local input
    local callable="${@:1:-1}" # all until last param
    local aggregate="${@[-1]}" # last param


    while read -r input; do
        aggregate="$("${callable[@]}" "${aggregate}" "${input}")"
    done
    echo "${aggregate}"
}
</syntaxhighlight>
</blockquote><!-- Reduce -->
</blockquote><!-- Reduce -->

Latest revision as of 19:45, 11 December 2022

Fancy loops that let you process things incrementally in a pipeline.
You'll almost never use these directly, but it might be inspiration for a more useful function.

NOTE:

If your callable accepts parameter as stdin, you don't need map/filter (ex. sed/grep work just fine from stdin).
you could also use xargs to pass stdin lines as callable params.


Filter

# Call callable/params($*), passing each each STDIN line as the last parameter
#
# EXAMPLE:
#   divisible_by_2() { [ $(($1 % 2)) -eq 0 ] }
#   echo {1..10} | tr ' ' '\n' | filter divisible_by_2
#   #> 2
#   #> 4
#   #> ...
#
filter() {
    local input

    while read -r input; do
        if "$@" "${input}" 2>&1 > /dev/null ;
            echo "${input}"
        fi
    done
}

Map

# Call callable/params($*), passing each each STDIN line as the last parameter
#
# EXAMPLE:
#   print_divisible_by_2() { 
#     [ $(($1 % 2)) -eq 0 ] && echo "$1:yes" || echo "$1:no"
#   }
#   echo {1..10} | tr ' ' '\n' | map print_divisible_by_2
#   #> 1:no
#   #> 2:yes
#   #> ...
#
map() {
    local input

    while read -r input; do
        "$@" "${input}"
    done
}

Reduce

# callable/params must accept aggregate as 2nd-last param, and input as last param.
#
# EXAMPLE:
#   sum() { echo $(($1 + $2)) }
#   echo {1..10} | tr ' ' '\n' | reduce sum 0
#   #> 55
#
reduce() {
    local input
    local callable="${@:1:-1}" # all until last param
    local aggregate="${@[-1]}" # last param

    while read -r input; do
        aggregate="$("${callable[@]}" "${aggregate}" "${input}")"
    done
    echo "${aggregate}"
}