Bienvenido a nuestra web, en este sitio vas a hallar la solucíon a lo que necesitas.
Solución:
Las bibliotecas para bash existen, pero no son comunes. Una de las razones por las que las bibliotecas bash son escasas se debe a la limitación de funciones. Creo que estas limitaciones se explican mejor en “Greg’s Bash Wiki”:
Funciones. Las “funciones” de Bash tienen varios problemas:
-
Reutilización de código: Las funciones Bash no devuelven nada; solo producen flujos de salida. Cada método razonable de capturar ese flujo y asignarlo a una variable o pasarlo como un argumento requiere un SubShell, que rompe todas las asignaciones a los ámbitos externos. (Consulte también BashFAQ / 084 para obtener trucos para recuperar resultados de una función). Por lo tanto, las bibliotecas de funciones reutilizables no son factibles, ya que no puede pedirle a una función que almacene sus resultados en una variable cuyo nombre se pasa como argumento (excepto realizando backflips de evaluación).
-
Alcance: Bash tiene un sistema simple de alcance local que se parece más o menos al “alcance dinámico” (por ejemplo, Javascript, elisp). Las funciones ven los locales de sus llamadores (como la palabra clave “no local” de Python), pero no pueden acceder a los parámetros posicionales de un llamador (excepto a través de BASH_ARGV si extdebug está habilitado). No se puede garantizar que las funciones reutilizables estén libres de colisiones de espacios de nombres a menos que recurra a reglas de nombres extrañas para hacer que los conflictos sean lo suficientemente improbables. Esto es particularmente un problema si se implementan funciones que esperan actuar sobre nombres de variables del marco n-3 que pueden haber sido sobrescritos por su función reutilizable en n-2. Ksh93 puede usar las reglas de alcance léxico más comunes declarando funciones con la sintaxis “nombre de función …” (Bash no puede, pero admite esta sintaxis de todos modos).
-
Cierres: En Bash, las funciones en sí son siempre globales (tienen “alcance de archivo”), por lo que no hay cierres. Las definiciones de funciones pueden estar anidadas, pero no son cierres, aunque se parecen mucho. Las funciones no son “pasables” (de primera clase) y no hay funciones anónimas (lambdas). De hecho, nada es “aceptable”, especialmente las matrices. Bash utiliza estrictamente la semántica de llamada por valor (excepto el truco de alias mágico).
-
Hay muchas más complicaciones que involucran: subcapas; funciones exportadas; “función colapsante” (funciones que definen o redefinen otras funciones o ellas mismas); trampas (y su herencia); y la forma en que las funciones interactúan con stdio. No muerda al novato por no entender todo esto. Las funciones de Shell están totalmente jodidas.
Fuente: http://mywiki.wooledge.org/BashWeakness
Un ejemplo de una “biblioteca” de shell es /etc/rc.d/functions en un sistema basado en Redhat. Este archivo contiene funciones comúnmente utilizadas en el script de inicio sysV.
Veo buena y mala información aquí. Permítanme compartir lo que sé, ya que bash es el idioma principal que uso en el trabajo (y construimos bibliotecas …). Google tiene un escrito decente sobre scripts bash en general que pensé que era una buena lectura: https://google.github.io/styleguide/shell.xml.
Permítanme comenzar diciendo que no debería pensar en una biblioteca bash como lo hace con las bibliotecas en otros idiomas. Hay ciertas prácticas que deben aplicarse para mantener una biblioteca en bash simple, organizada y, lo más importante, reutilizable.
No existe el concepto de devolver nada de una función bash excepto las cadenas que imprime y el estado de salida de la función (0-255). Aquí se esperan limitaciones y una curva de aprendizaje, especialmente si está acostumbrado a las funciones de los lenguajes de nivel superior. Puede ser extraño al principio, y si se encuentra en una situación en la que las cuerdas simplemente no lo cortan, querrá aprovechar una herramienta externa como jq. Si jq (o algo parecido) está disponible, puede comenzar a hacer que sus funciones impriman la salida formateada para ser analizada y utilizada como lo haría con un objeto, arrayetc.
Declaraciones de funciones
Hay dos formas de declarar una función en bash. Uno opera dentro de su shell actual, lo llamaremos Fx0. Y uno genera una subcapa para operar, lo llamaremos Fx1. A continuación, se muestran ejemplos de cómo se declaran:
Fx0() echo "Hello from $FUNCNAME";
Fx1()( echo "Hello from $FUNCNAME" )
Estas 2 funciones realizan la misma operación, de hecho. Sin embargo, hay una key diferencia aquí. Fx1 no puede realizar ninguna acción que altere el shell actual. Eso significa modificar variables, cambiar opciones de shell y declarando otras funciones. Esto último es lo que se puede aprovechar para evitar problemas de espaciado de nombres que pueden surgir con facilidad.
# Fx1 cannot change the variable from a subshell
Fx0() Fx=0;
Fx1()( Fx=1 )
Fx=foo; Fx0; echo $Fx
# 0
Fx=foo; Fx1; echo $Fx
# foo
Dicho esto, la única vez que debería utilizar una función del tipo “Fx0” es cuando desee volver a declarar algo en el shell actual. Utilice siempre las funciones “Fx1” porque son más seguras y no tiene que preocuparse por el nombre de las funciones declaradas dentro de ellas. Como puede ver a continuación, la función inocente se sobrescribe dentro de Fx1, sin embargo, permanece ilesa después de la ejecución de Fx1.
innocent_function()(
echo ":)"
)
Fx1()(
innocent_function()( true )
innocent_function
)
Fx1 #prints nothing, just returns true
innocent_function
# :)
Esto tendría (probablemente) consecuencias no deseadas si hubiera usado llaves. Ejemplos de funciones útiles de tipo “Fx0” serían específicamente para cambiar el shell actual, así:
use_strict()
set -eEu -o pipefail
enable_debug()
set -Tx
disable_debug()
set +Tx
Respecto a las declaraciones
El uso de variables globales, o al menos aquellas que se espera que tengan un valor, es una mala práctica en todos los sentidos. Mientras construye una biblioteca en bash, nunca querrá que una función dependa de una variable externa que ya está configurada. Todo lo que necesite la función se le debe proporcionar a través de los parámetros posicionales. Este es el principal problema que veo en las bibliotecas que otras personas intentan construir en bash. Incluso si encuentro algo interesante, no puedo usarlo porque no conozco los nombres de las variables que necesito establecer de antemano. Me lleva a investigar todo el código y, en última instancia, a elegir las piezas útiles para mí. De lejos, las mejores funciones para crear para una biblioteca son extremadamente pequeñas y no utilizan variables con nombre en absoluto, ni siquiera localmente. Tome lo siguiente, por ejemplo:
serviceClient()(
showUsage()(
echo "This should be a help page"
) >&2
isValidArg()(
test "$(type -t "$1")" = "function"
)
isRunning()(
nc -zw1 "$(getHostname)" "$(getPortNumber)"
) &>/dev/null
getHostname()(
echo localhost
)
getPortNumber()(
echo 80
)
getStatus()(
if isRunning
then echo OK
else echo DOWN
fi
)
getErrorCount()(
grep -c "ERROR" /var/log/apache2/error.log
)
printDetails()(
echo "Service status: $(getStatus)"
echo "Errors logged: $(getErrorCount)"
)
if isValidArg "$1"
then "$1"
else showUsage
fi
)
Normalmente, lo que vería cerca de la parte superior es local hostname=localhost
y local port_number=80
lo cual está bien, pero no es necesario. En mi opinión, estas cosas deben funcionalizarse a medida que se construye para evitar futuros dolores cuando, de repente, es necesario introducir alguna lógica para obtener un valor, como: if isHttps; then echo 443; else echo 80; fi
. No desea que ese tipo de lógica se coloque en su función principal o de lo contrario lo hará rápidamente feo e inmanejable. Ahora, serviceClient tiene funciones internas que se declaran tras la invocación, lo que agrega una cantidad imperceptible de sobrecarga a cada ejecución. El beneficio es que ahora puede tener service2Client con funciones (o funciones externas) que tienen el mismo nombre que serviceClient sin ningún conflicto. Otra cosa importante a tener en cuenta es que las redirecciones se pueden aplicar a una función completa al declararla. ver: isRunning o showUsage Esto se acerca tanto a la orientación a objetos como creo que debería molestarse en usar bash.
. serviceClient.sh
serviceClient
# This should be a help page
if serviceClient isRunning
then serviceClient printDetails
fi
# Service status: OK
# Errors logged: 0
Espero que esto ayude a mis compañeros hackers de bash.
Aquí hay una lista de “digno de tu tiempo” bibliotecas bash que encontré después de pasar una hora más o menos buscando en Google.
- https://github.com/mietek/bashmenot/
bashmenot es una biblioteca que utilizan Halcyon y Haskell en Heroku. El enlace anterior apunta a una lista completa de funciones disponibles con ejemplos: calidad, cantidad y documentación impresionantes.
- http://marcomaggi.github.io/docs/mbfl.html
MBFL ofrece un conjunto de módulos que implementan operaciones comunes y una plantilla de script. Proyecto bastante maduro y todavía activo en github
- https://github.com/javier-lopez/learn/blob/master/sh/lib
Debe mirar el código para obtener una breve descripción y ejemplos. Tiene unos años de desarrollo a sus espaldas.
- https://github.com/martinburger/bash-common-helpers
Tiene la menor cantidad de funciones básicas. Para la documentación también tienes que mirar el código.