2009-01-15 13 views
18

¿Hay alguna manera de implementar/usar funciones lambda en bash? Estoy pensando en algo como:funciones lambda en bash

$ someCommand | xargs -L1 (lambda function) 

Respuesta

19

No sé de una manera de hacer esto, sin embargo, puede ser capaz de lograr lo que estamos tratando de hacer usando:

somecommand | while read -r; do echo "Something with $REPLY"; done 

Esto también será más rápido, ya que no creará un nuevo proceso para cada línea de texto.

[EDIT] 2009-07-09 que he hecho dos cambios:

  1. Incorporated sugerencia de litb de utilizar -r a deshabilitar el procesamiento de barra invertida - esto significa que se pasarán las barras invertidas en la entrada a través de sin cambios.
  2. En lugar de proporcionar un nombre de variable (como X) como parámetro a read, dejamos que read asigne su variable predeterminada, REPLY. Esto tiene el agradable efecto secundario de preservar los espacios iniciales y finales, que de lo contrario se eliminan (a pesar de que se conservan los espacios internos).

Según mis observaciones, todos estos cambios combinados conservan todo, excepto los caracteres NUL (ASCII 0) literales en cada línea de entrada.

[EDIT 26/7/2016]

Según Evi1M4chine comentarista, el establecimiento de $IFS en la cadena vacía antes de ejecutar read X (por ejemplo, con el comando IFS='' read X) también deben preservar espacios al principio y al final, cuando almacenando el resultado en $X, lo que significa que no está obligado a usar $REPLY.

+1

+1, que es increíble! – orip

+0

Supongo que el problema que he tenido en el pasado con este método es que funciona muy bien para cadenas que no tienen espacios. Si, por ejemplo, la salida de es una lista de archivos, algunos de los cuales tienen espacios, falla la "lectura X". He leído en algún lugar cómo lidiar con eso, pero nunca recuerdo los detalles. – Daniel

+0

Siento tu dolor ... De hecho, "leer X" * casi * hace lo correcto; conserva los espacios internos, pero si una línea comienza o termina con espacios, estos se eliminarán. Por cierto, el comando xargs del OP se divide en espacios internos (e incluso concatenan líneas * terminando * en espacios debido a "-L1"!) –

3

¿Qué tal esto?

somecommand | xargs -d"\n" -I{} echo "the argument is: {}" 

(asume cada argumento es una línea, de lo contrario cambiar delimitador)

1

si desea que sólo xargs (debido opción paralela -P N por ejemplo), y sólo bash como código de función, entonces bash -c se puede utilizar como parámetro para xargs.

seq 1 10 | tr '\n' '\0' | xargs -0 -n 1 bash -c 'echo any bash code $0' 

tr y -0 opción se utilizan aquí para deshabilitar cualquier sustitución de parámetros xargs.

7

si quieres funciones verdaderas, y no solo tubos o bucles while (por ejemplo, si quieres pasarlos por ahí, como si fueran datos) simplemente no haría lambdas, y definir funciones ficticias con un nombre ficticio recurrente , para usar de inmediato, y tirar después. De este modo:

# An example map function, to use in the example below. 
map() { local f="$1"; shift; for i in "[email protected]"; do "$f" "$i"; done; } 

# Lambda function [λ], passed to the map function. 
λ(){ echo "Lambda sees $1"; }; map λ * 

Al igual que en los lenguajes funcionales adecuados, no hay necesidad de pasar parámetros, como se puede envolver en un cierre:

# Let’s say you have a function with three parameters 
# that you want to use as a lambda: 
# (As in: Partial function application.) 
trio(){ echo "$1 Lambda sees $3 $2"; } 

# And there are two values that you want to use to parametrize a 
# function that shall be your lambda. 
pre="<<<" 
post=">>>" 

# Then you’d just wrap them in a closure, and be done with it: 
λ(){ trio "$pre" "$post" "[email protected]"; }; map λ * 

yo diría que es incluso más corto que todos los demás soluciones presentadas aquí.

+0

¿Puede definir una función desde el interior del cuerpo de otra función? Porque de eso es lo que se trata lambda – pqnet

+0

@pqnet: La diferencia principal con una función normal es que las lambdas son anónimas y están definidas en línea. Lo que los hace convenientes para usar como parámetros y generalmente en expresiones. Muchos lenguajes permiten definir funciones en funciones de una manera que no son lambdas. No creo que 'bash' permita definir funciones en línea, ni anónimamente. Pero definitivamente permite pasarlos como parámetros, incluso en el cierre de la función pasada, y hacer que sus nombres sean casi anónimos. Por lo tanto, aunque mi respuesta necesariamente no es una lambda completa, es lo más cercano que obtendrás. – Evi1M4chine

+0

Para una pregunta sobre cómo pasar realmente el código anónimo, consulte: http://unix.stackexchange.com/questions/81202/passing-a-code-block-as-an-anon-function Aunque es un desastre. :) – Evi1M4chine

0

Sí. Uno puede pasar una variable de cadena que representa una llamada de comando y luego ejecutar el comando con eval.

Ejemplo:

command='echo howdy' 
eval "$command" 
Cuestiones relacionadas