将代码块作为匿名传递。功能

将代码块作为匿名传递。功能

是否可以将命令块视为匿名函数?

function wrap_this {
   run_something
   # Decide to run block or maybe not.
   run_something else
}

wrap_this {
   do_something
   do_somthing else
}

# Do something else

wrap_this {
   do_something_else_else
   do_something_else_else_else
}

(我意识到您为每个块创建一个函数或文件,但我发现此选项在某些情况下更清晰且更易于阅读。)

while与 一起执行do/donefunction与 一起执行{ multiple lines }。我意识到 BASH 没有匿名函数,但是是否可以将多个命令传递给另一个函数,就像定义函数或时所做的那样while

答案1

这是我能想到的最短的解决方案:

鉴于这些功能:

# List processing
map() { while IFS='' read -r x; do "$@" "$x"; done; }
filter() { while IFS='' read -r x; do "$@" "$x" >&2 && echo "$x"; done; }
foldr() { local f="$1"; local result="$2"; shift 2;  while IFS='' read -r x; do result="$( "$f" "$@" "$x" "$result" )"; done; echo "$result"; }
foldl() { local f="$1"; local result="$2"; shift 2;  while IFS='' read -r x; do result="$( "$f" "$@" "$result" "$x" )"; done; echo "$result"; }

# Helpers
re() { [[ "$2" =~ $1 ]]; }

例子:

# Example helpers
toLower() { tr '[:upper:]' '[:lower:]'; }
showStructure() { [[ "$1" == "--curly" ]] && echo "{$2; $3}" || echo "($1, $2)"; }

# All lib* directories, ignoring case, using regex
ls /usr | map toLower | filter re 'lib.*'

# All block devices. (Using test, for lack of a full bash [[ … ]].)
cd /dev; ls | filter test -b

# Show difference between foldr and foldl
$ ls / | foldr showStructure '()'
(var/, (usr/, (tmp/, (sys/, (sbin/, (run/, (root/, (proc/, (opt/, (mnt/, (media/, (lost+found/, (lib64/, (lib32/, (lib@, (home/, (etc/, (dev/, (daten/, (boot/, (bin/, ())))))))))))))))))))))
$ ls / | foldr showStructure '{}' --curly
{var/; {usr/; {tmp/; {sys/; {sbin/; {run/; {root/; {proc/; {opt/; {mnt/; {media/; {lost+found/; {lib64/; {lib32/; {lib@; {home/; {etc/; {dev/; {daten/; {boot/; {bin/; {}}}}}}}}}}}}}}}}}}}}}}

(这些示例当然只是用法示例,实际上,这种风格只对更复杂的用例有意义。)

一般来说,可以使用以下样式:

f() { something "$@"       ; }; someList    | map    f
g() { something "$1" "$2" …; }; someCommand | filter g
⋮                              ⋮            ⋮     ⋮

它不是相当lambda,但它非常非常接近。只有几个多余的字符。

但据我所知,以下任何方便的缩写都不起作用:

λ() { [[ $@ ]]; } # fails on spaces
λ() { [[ "${@:-1}" ${@:1:-1} ]]; } # syntax error
alias λ=test # somehow ignored

不幸的是,bash它不太适合这种风格,尽管它的一些功能具有非常实用的风格。

答案2

我已经成功地通过黑客做了你想做的事eval。我以此警告说eval 是不安全的,你应该不惜一切代价避免。话虽如此,如果您相信您的代码不会被滥用,您可以使用:

wrap_this(){
    run_something
    eval "$(cat /dev/stdin)"
    run_something_else
}

这允许您运行代码如下:

wrap_this << EOF
    my function
EOF

并不完全理想,因为内部块是一个字符串,但确实创建了重用。

答案3

不,bash 没有匿名函数。然而,可以将函数名称和参数作为字符串传递,并让 bash 调用它。

function wrap() {
    do_before
    "$@"
    do_after
}

wrap do_something with_arguments

然而,这有些有限。处理引用可能会成为一个问题。传递多个命令也是一件复杂的事情。

答案4

您可以unset在定义并使用函数后立即调用以删除该函数。虽然这不会创建真正的匿名函数,但该函数将无法在调用站点附近之外使用。

function anon_fn {
    echo 123
}
anon_fn
unset anon_fn

相关内容