Passando um bloco de códigos como um anon. função

7

É possível tratar um bloco de comandos como uma função anônima?

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
}

(Eu percebo que você criou uma função ou arquivo para cada bloco, mas eu acho esta opção mais clara e fácil de ler em certas situações.)

while faz isso com do/done e function faz isso com { multiple lines } . Eu percebo BASH não tem funções anônimas, mas é possível passar vários comandos para outra função, como você pode fazer ao definir uma função ou while ?

    
por dgo.a 30.06.2013 / 11:35

4 respostas

2

Esta é a solução mais curta que eu pude pensar:

Dadas estas funções:

# 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 ]]; }

Exemplos:

# 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/; {}}}}}}}}}}}}}}}}}}}}}}

(Esses exemplos são apenas exemplos de uso e, na realidade, esse estilo só faria sentido para casos de uso mais complicados.)

Geralmente, o estilo a seguir sempre pode ser usado:

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

Não é bastante lambda, mas está muito próximo. Apenas alguns caracteres em excesso.

Mas qualquer uma das seguintes abreviações de conveniência não funciona tanto quanto eu posso dizer:

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

Infelizmente, bash não é muito adequado para esse estilo, embora alguns de seus recursos tenham um estilo muito funcional.

    
por 29.12.2016 / 00:27
3

Você pode colocar o código em uma string e passá-lo para eval ou sh ou simplesmente interpolá-lo.

perform () {
  "$@"
}

perform echo "moo"

Você pode acabar rapidamente com problemas profundos de cotação.

    
por 30.06.2013 / 13:32
3

Não, o bash não tem funções anônimas. No entanto, é possível passar um nome de função e argumentos como strings e chamá-lo de bash.

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

wrap do_something with_arguments

No entanto, isso é um pouco limitado. Lidar com citações pode se tornar um problema. Passar mais de um comando também é uma complicação.

    
por 30.06.2013 / 12:06
0

Eu consegui fazer o que você quer com um eval hack. Com isso eu fiquei avisado que eval é inseguro e você deve evitar a todo custo . Tendo dito isso, se você acredita que seu código não será usado indevidamente, você pode usar isto:

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

Isso permite que você execute o código da seguinte forma:

wrap_this << !!
    my function
!!

Não é exatamente ideal, já que o bloco interno é uma string, mas cria reutilização.

    
por 15.11.2017 / 17:08

Tags