¿Cuál es el equivalente zsh de bash export -f


24

Entonces empecé a usar zsh. Me gusta todo bien. Parece genial y resbaladizo, y el hecho de que el directorio de trabajo actual y la línea de comando real estén en diferentes líneas es agradable, pero al mismo tiempo, me doy cuenta de que zshpuede ser un poco más lento que bash, especialmente cuando se imprime texto en el pantalla.

Lo que más me gustó fue el hecho de que zshera 'compatible con versiones anteriores' con todas las funciones que definí en mi .bashrc.

Sin embargo, una queja. Todas las funciones funcionan perfectamente, pero no puedo entender cómo funciona el sistema de exportación.

Exporté algunas de esas .bashrcfunciones para poder usarlas en otros lugares, como scripts y programas externos, con export -f.

En zsh, parece que ni siquiera se habla de exportar. ¿Es de carga automática? ¿Son esas dos cosas iguales? Me está costando mucho trabajo descubrirlo.


2
Esta es una pregunta muy antigua, pero quiero decir que "el directorio de trabajo actual y la línea de comando real están en líneas diferentes" no tiene nada que ver con zsh. Depende de cómo configure su indicador, eso es todo.
4ae1e1

Respuestas:


11

Las variables de entorno que contienen funciones son un hack bash. Zsh no tiene nada similar. Puede hacer algo similar con unas pocas líneas de código. Las variables de entorno contienen cadenas; versiones anteriores de bash, antes de que se descubriera Shellshock , almacenaban el código de la función en una variable cuyo nombre es el de la función y cuyo valor es () {seguido por el código de la función seguido de }. Puede usar el siguiente código para importar variables con esta codificación e intentar ejecutarlas con configuraciones similares a bash. Tenga en cuenta que zsh no puede emular todas las funciones de bash, todo lo que puede hacer es acercarse un poco (por ejemplo, para $foodividir el valor y expandir los comodines, y hacer matrices basadas en 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Como señaló Stéphane Chazelas , el descubridor original de Shellshock, una versión anterior de esta respuesta podría ejecutar un código arbitrario en este punto si la definición de la función estaba mal formada. Esta versión no lo hace, pero, por supuesto, tan pronto como ejecute cualquier comando, podría ser una función importada del entorno).

Las versiones posteriores al shellshock de bash codifican funciones en el entorno utilizando nombres de variables no válidos (por ejemplo BASH_FUNC_myfunc%%). Esto los hace más difíciles de analizar de manera confiable ya que zsh no proporciona una interfaz para extraer dichos nombres de variables del entorno.

No recomiendo hacer esto. Confiar en las funciones exportadas en los scripts es una mala idea: crea una dependencia invisible en su script. Si alguna vez ejecuta su script en un entorno que no tiene su función (en otra máquina, en un trabajo cron, después de cambiar sus archivos de inicialización de shell, ...), su script ya no funcionará. En su lugar, almacene todas sus funciones en uno o más archivos separados (algo así como ~/lib/shell/foo.sh) e inicie sus scripts importando las funciones que usa ( . ~/lib/shell/foo.sh). De esta manera, si modifica foo.sh, puede buscar fácilmente qué scripts dependen de él. Si copia una secuencia de comandos, puede averiguar fácilmente qué archivos auxiliares necesita.

Zsh (y ksh antes) lo hace más conveniente al proporcionar una forma de cargar automáticamente las funciones en los scripts donde se usan. La restricción es que solo puede poner una función por archivo. Declare la función como autocargada y coloque la definición de la función en un archivo cuyo nombre sea el nombre de la función. Coloque este archivo en un directorio listado $fpath(que puede configurar a través de la FPATHvariable de entorno). En su script, declare funciones cargadas automáticamente con autoload -U foo.

Además, zsh puede compilar scripts para ahorrar tiempo de análisis. Llame zcompilepara compilar un guión. Esto crea un archivo con la .zwcextensión. Si este archivo está presente autoload, cargará el archivo compilado en lugar del código fuente. Puede usar la zrecompilefunción para (re) compilar todas las definiciones de funciones en un directorio.


1
Es curioso cómo su código tiene la misma vulnerabilidad shellshock bash(no verifica que el contenido de la variable es solo una definición de función y procesa cualquier nombre de variable como HTTP_HOSTo LC_X). Buena respuesta de lo contrario.
Stéphane Chazelas

@ StéphaneChazelas Si va a ejecutar comandos con funciones importadas del entorno, prácticamente ha perdido. Pero he actualizado el código de importación para no ejecutar código arbitrario. Sin embargo, no es muy útil, ya que post-shellshock bash no codifica sus funciones exportadas de la misma manera.
Gilles 'SO- deja de ser malvado'

Ahora ha corregido el equivalente de CVE-2014-6271, pero probablemente todavía esté expuesto a muchas vulnerabilidades del tipo de CVE-2014-6277 / 6278 ... ya que todavía está exponiendo el analizador zsh al código en cualquier variable incluidos algunos que están potencialmente bajo el control de los atacantes en algunos contextos (ya que el código zsh -c 'functions[f]=$VAR' se analiza incluso si la ffunción nunca se llama). La solución es considerar solo las variables cuyo nombre sigue una plantilla reservada como esas $BASH_FUNC_x%%, pero como usted dice, zshno tiene API para enumerarlas o recuperarlas. Tendría que llamar perlpor ejemplo.
Stéphane Chazelas

7

Si coloca su declaración de función en .zshenv , podrá utilizar su función desde un script sin ningún esfuerzo.


¿Por qué rechazaste mi respuesta? Por favor explique.
Rools

¡Todavía estoy esperando una respuesta y sigo trabajando!
rools

Acabo de descubrir esta respuesta y es una solución ideal.
AFH

No lo rechacé. Y TBH, el OP preguntaba por exportar cosas de .bashrc, lo cual es una mala idea, mejor incluirlo en un script para que no termine con un entorno enorme. Pero su solución es solo una variante de esa misma mala idea, ponga todos sus scripts .zshenvy ralentiza cada invocación de zsh al analizar una gran cantidad de código que nunca se usa. Además, no es lo mismo que exportar una función, al igual que una variable exportada, una función exportada solo está disponible para procesos secundarios. Mientras que las cosas que pones .zshenvestán disponibles para todos los zsh.
Metamórfico el

Finalmente, si confía en el código personal que puso en su .zshenv, entonces todos sus scripts serán totalmente no portables. Normalmente los scripts podrían depender unos de otros, lo cual está bien, los distribuyes juntos. Pero si dependen de tener funciones especiales .zshenv, nadie querrá usarlas, o tendrían que ser invocadas con una especial ZDOTDIR, evitando que la suya .zshenvsea ​​ejecutada. Sería un dolor.
Metamórfico el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.