코드 블록을 익명으로 전달합니다. 기능

코드 블록을 익명으로 전달합니다. 기능

명령 블록을 익명 함수로 처리할 수 있습니까?

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/done하고 function로 수행합니다 { 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
⋮                              ⋮            ⋮     ⋮

그렇지 않다상당히람다, 하지만 아주 아주 가깝습니다. 추가 문자는 몇 개뿐입니다.

그러나 내가 아는 한 다음과 같은 편리한 약어는 작동하지 않습니다.

λ() { [[ $@ ]]; } # 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

관련 정보