Anonymous functions in shell scripts

2019-04-03 06:55发布

问题:

Is it possible to create something analogous to an anonymous function whose value can be assigned to an array element and later called? I can't seem to find a way to do this in a bash script but perhaps there's a workaround.

回答1:

Short answer: No.

Long answer: Nooooooooooooo.

Complete answer: Functions in bash are not first-class objects, therefore there can be no such thing as an anonymous function in bash.



回答2:

If you really need array to store the functions, you can define named functions and store just their names. You can then call the function as ${array[n]}. Or, you can name them func1 .. funcN and then just call func$n.



回答3:

It is possible; I wrote a library to do exactly this, though it's a very strange project. The source code is available at http://github.com/spencertipping/bash-lambda. Using this library:

$ my_array=()
$ my_array[0]=$(fn x 'echo $((x + 1))')
$ my_array[1]=$(fn x 'echo $((x + 2))')
$ ${my_array[0]} 5
6
$ ${my_array[1]} 5
7
$

The trick is to have the fn function create a file containing the body of the function, chmod +x that file, then return its name. This causes stray files to accumulate, which is why the library also implements an asynchronous mark/sweep garbage collector.



回答4:

The common technique is to assign function definitions conditionally:

#!/bin/sh

case $1 in
a) foo() { echo case a; };;
b) foo() { echo case b; };;
*) foo() { echo default; } ;;
esac

foo


回答5:

Create the fn file in your PATH

#!/bin/sh

printusage () {
        printf "Create anonymous function, for example\n"
        printf "fn 'echo "$1 $2"'"
        exit 1
}


[ "$#" = "1" ] || printusage
fun=$1
[ "$fun" = "" ] && printusage
fun_file="$(mktemp /tmp/fun_XXXXXX)"

echo "#!/bin/sh" > "$fun_file"
echo "" >> "$fun_file"
echo "$fun" >> "$fun_file"
chmod u+x "$fun_file"

echo "$fun_file"

You can then do :

foo=$(fn 'echo $1')
${foo} "bar" 


回答6:

well bash is turing complete, soo thats perfectly possible ;)

but aside from this its not really worth the consideration.

you could simulate such behaviour though with something along this line:

echo myval ; ( foocmd "$_" && barcmd "$_" )

but why?!?



标签: bash shell