¿Hay alguna forma de source
un script de shell en un espacio de nombres, preferiblemente un script de shell bash, pero buscaría otros shells si tuvieran esta característica y bash no?
Lo que quiero decir con eso es, por ejemplo, algo como "prefijar todos los símbolos definidos con algo para que no choquen con símbolos ya definidos (nombres de variables, nombres de funciones, alias)" o cualquier otra instalación que evite las colisiones de nombres.
Si hay una solución en la que pueda el espacio de nombres en el source
momento ( NodeJS
estilo), sería lo mejor.
Código de ejemplo:
$ echo 'hi(){ echo Hello, world; }' > english.sh
$ echo 'hi(){ echo Ahoj, světe; }' > czech.sh
$ . english.sh
$ hi
#=> Hello, world
$ . czech.sh #bash doesn't even warn me that `hi` is being overwritten here
$ hi
#=> Ahoj, světe
#Can't use the English hi now
#And sourcing the appropriate file before each invocation wouldn't be very efficient
( easiest thing ever )
. Pero eso no es exactamente lo que buscas. Supongo que podría hacerlo( stuff in subshell; exec env ) | sed 's/^/namespace_/'
yeval
el resultado en el shell principal, pero eso es un poco desagradable.ksh93
. Los espacios de nombres son fundamentales, y todos sus tipos de nombres (que también se pueden escribir) admiten espacios de nombres. También es mucho más rápido en prácticamente todos los aspectos quebash
, por cierto.env | sed ...
funcionaría para variables, podría hacerset
para obtener funciones, pero la búsqueda y el reemplazo serían un problema: las funciones pueden llamarse entre sí y usted necesitaría reemplazar todas las invocaciones cruzadas con invocaciones cruzadas prefijadas pero sin reemplazar el mismas palabras en otra parte del código de definición de función, donde no es una invocación. Para eso, necesitaría un analizador de bash, no solo una expresión regular, y todavía funcionaría siempre que las funciones no se llamaran entre sí a través de eval.Respuestas:
Desde
man ksh
un sistema con unksh93
...Y, para demostrar, aquí está el concepto aplicado a un espacio de nombres proporcionado por defecto para cada variable de shell regular asignada en un
ksh93
shell. En el siguiente ejemplo, definiré unadiscipline
función que actuará como el.get
método asignado para la$PS1
variable de shell. Cada variable de shell básicamente obtiene su propio espacio de nombres con, al menos, el valor predeterminadoget
,set
,append
, yunset
métodos. Después de definir la siguiente función, cada vez que$PS1
se hace referencia a la variable en el shell, la salida dedate
se dibujará en la parte superior de la pantalla ...(También tenga en cuenta la falta de la
()
subshell en la sustitución del comando anterior)Técnicamente, los espacios de nombres y las disciplinas no son exactamente lo mismo (porque las disciplinas se pueden definir para aplicarse global o localmente a un espacio de nombres en particular ) , pero son parte integral de la conceptualización de los tipos de datos de shell que es fundamental para
ksh93
.Para abordar sus ejemplos particulares:
...o...
fuente
He escrito una función de shell POSIX que podría ser utilizado para espacio de nombres local una orden interna del shell o función en cualquiera de
ksh93
,dash
,mksh
, obash
(nombrado específicamente porque he confirmado personalmente al trabajo en todos ellos) . De los proyectiles en los que lo probé, solo no cumplió con mis expectativasyash
y nunca esperé que funcionara en absolutozsh
. No hice la pruebaposh
. Renuncié a cualquier esperanza haceposh
un tiempo y no la he instalado en algún tiempo. Tal vez funciona enposh
...?Digo que es POSIX porque, al leer la especificación, aprovecha un comportamiento específico de una utilidad básica, pero, es cierto, la especificación es vaga a este respecto y, al menos, una persona aparentemente no está de acuerdo conmigo. En general, he tenido un desacuerdo con este, eventualmente he encontrado que el error es mío, y posiblemente esta vez también me equivoque con respecto a la especificación, pero cuando lo pregunté más, no respondió.
Sin embargo, como dije, esto definitivamente funciona en los shells mencionados anteriormente, y funciona, básicamente, de la siguiente manera:
El
command
comando se especifica como una utilidad básicamente disponible y una de las$PATH
funciones integradas previamente. Una de sus funciones especificadas es envolver utilidades incorporadas especiales en su propio entorno cuando las llama, y así ...... el comportamiento de las dos asignaciones de línea de comandos anteriores es correcto por especificación. El comportamiento de ambas condiciones de error también es correcto y, de hecho, está casi completamente duplicado allí desde la especificación. Las asignaciones prefijadas a las líneas de comando de funciones o componentes incorporados especiales se especifican para afectar el entorno actual del shell. Del mismo modo, los errores de redireccionamiento se especifican como fatales cuando se apunta a cualquiera de ellos.
command
se especifica para suprimir el tratamiento especial de las incorporaciones especiales en esos casos, y el caso de redirección se demuestra realmente con un ejemplo en la especificación.Las construcciones regulares, como
command
, por otro lado, se especifican para ejecutarse en un entorno de subshell , lo que no necesariamente significa que sea de otro proceso , solo que debería ser fundamentalmente indistinguible de uno. Los resultados de llamar a un builtin regular siempre deben parecerse a lo que se podría obtener de un$PATH
comando 'd' igualmente capaz . Y entonces...Pero el
command
comando no puede llamar a las funciones de shell y, por lo tanto, no se puede usar para representar su tratamiento especial discutible como se puede hacer para las incorporaciones regulares. Eso también se especifica. De hecho, la especificación dice que una utilidad principal decommand
es que puede usarla dentro de una función de envoltura de envoltorio nombrada por otro comando para llamar a ese otro comando sin auto-recursión porque no llamará a la función. Me gusta esto:Si no lo usó
command
allí, lacd
función casi definitivamente sería predeterminada para la autorrecurrencia.Pero como un builtin normal que puede llamar builtins especiales,
command
puede hacerlo en un entorno de subshell . Y así, si bien el estado actual del shell definido en el interior podría adherirse al shell actual, ciertamenteread
,$var1
y lo$var2
hizo, al menos los resultados de las definiciones de la línea de comandos probablemente no deberían ...Ahora, no
command
sé si la capacidad de ser tanto un constructor regular como llamar directamente a construcciones especiales es solo una especie de escapatoria inesperada con respecto a la línea de comandos, no sé, pero sí sé que al menos las cuatro conchas ya mencionó honrar elcommand
espacio de nombres.Y aunque
command
no puede llamar directamente a las funciones de shell, puede llamareval
como se demostró, y puede hacerlo indirectamente. Así que construí un contenedor de espacio de nombres sobre este concepto. Toma una lista de argumentos como:... excepto que la
command
palabra anterior solo se reconoce como una si se puede encontrar con un vacío$PATH
. Además de la determinación del alcance localmente variables de shell nombradas en la línea de comandos, sino que también a nivel local-ámbitos toda variables con nombres individuales minúsculas del alfabeto y una lista de otros estándares, tales como$PS3
,$PS4
,$OPTARG
,$OPTIND
,$IFS
,$PATH
,$PWD
,$OLDPWD
y algunos otros.Y sí, por la determinación del alcance localmente el
$PWD
y$OLDPWD
las variables y después explícitamentecd
ing a$OLDPWD
y$PWD
que puede con bastante fiabilidad alcance el directorio de trabajo actual también. Esto no está garantizado, aunque se esfuerza bastante. Conserva un descriptor para7<.
y cuando su objetivo de ajuste vuelve, lo hacecd -P /dev/fd/7/
. Si el directorio de trabajo actual ha estadounlink()
en el ínterin, al menos aún debería volver a cambiar, pero emitirá un error feo en ese caso. Y debido a que mantiene el descriptor, tampoco creo que un núcleo cuerdo deba permitir que su dispositivo raíz se desmonte (???) .También localiza las opciones de shell y las restaura al estado en el que las encontró cuando regresa su utilidad envuelta. Se trata
$OPTS
especialmente porque mantiene una copia en su propio alcance al que inicialmente asigna el valor$-
. Después de manejar también todas las asignaciones en la línea de comandos, lo haráset -$OPTS
justo antes de invocar su objetivo de ajuste. De esta manera, si define-$OPTS
en la línea de comandos, puede definir las opciones de shell de su objetivo de ajuste. Cuando el objetivo regrese, lo haráset +$- -$OPTS
con su propia copia$OPTS
(que no se ve afectada por la línea de comandos que define) y restaurará todo al estado original.Por supuesto, no hay nada que
returrn
impida que la persona que llama de alguna manera salga explícitamente de la función a través del objetivo de ajuste o sus argumentos. Si lo hace, evitará cualquier restauración / limpieza de estado que de lo contrario intentaría.Para hacer todo lo que necesita, debe ir a tres
eval
de profundidad. Primero se envuelve en un ámbito local, luego, desde adentro, lee argumentos, los valida para nombres de shell válidos y se cierra con error si encuentra uno que no lo es. Si todos los argumentos son válidos y eventualmente uno hacecommand -v "$1"
que devuelva verdadero (recordar:$PATH
está vacío en este punto) ,eval
la línea de comandos define y pasa todos los argumentos restantes al objetivo de ajuste (aunque ignora el caso especial parans
, porque eso no No sea muy útil, y treseval
s de profundidad es más que suficiente) .Básicamente funciona así:
Hay algunas otras redirecciones y, y algunas pruebas extrañas que ver con la forma
c
en que se colocan algunos proyectiles$-
y luego se niegan a aceptarlo como una opción paraset
(???) , pero todo es auxiliar, y se usa principalmente solo para evitar la emisión salida no deseada y similar en casos extremos. Y así es como funciona. Puede hacer esas cosas porque establece su propio ámbito local antes de llamar a su utilidad envuelta en un anidado.Es largo, porque trato de tener mucho cuidado aquí: tres
evals
es difícil. Pero con eso puedes hacer:Ir un paso más allá y espaciar de forma persistente el alcance local de la utilidad envuelta no debería ser muy difícil. E incluso como está escrito, ya define una
$LOCALS
variable para la utilidad envuelta que se compone de solo una lista separada por espacios de todos los nombres que definió en el entorno de la utilidad envuelta.Me gusta:
... que es perfectamente seguro:
$IFS
se ha desinfectado a su valor predeterminado y solo los nombres de shell válidos lo hacen a$LOCALS
menos que lo configure usted mismo en la línea de comando. E incluso si puede haber caracteres globales en una variable dividida, también puede establecerOPTS=f
en la línea de comandos que la utilidad envuelta prohíba su expansión. En todo caso:Y aquí está la función. Todos los comandos tienen el prefijo w /
\
para evitaralias
expansiones:fuente