¿Hay alguna forma de sourceun 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 sourcemomento ( NodeJSestilo), 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_/'yevalel 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 hacersetpara 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 kshun 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
ksh93shell. En el siguiente ejemplo, definiré unadisciplinefunción que actuará como el.getmétodo asignado para la$PS1variable de shell. Cada variable de shell básicamente obtiene su propio espacio de nombres con, al menos, el valor predeterminadoget,set,append, yunsetmétodos. Después de definir la siguiente función, cada vez que$PS1se hace referencia a la variable en el shell, la salida dedatese 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 expectativasyashy nunca esperé que funcionara en absolutozsh. No hice la pruebaposh. Renuncié a cualquier esperanza haceposhun 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
commandcomando se especifica como una utilidad básicamente disponible y una de las$PATHfunciones 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.
commandse 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$PATHcomando 'd' igualmente capaz . Y entonces...Pero el
commandcomando 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 decommandes 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ó
commandallí, lacdfunción casi definitivamente sería predeterminada para la autorrecurrencia.Pero como un builtin normal que puede llamar builtins especiales,
commandpuede 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,$var1y lo$var2hizo, al menos los resultados de las definiciones de la línea de comandos probablemente no deberían ...Ahora, no
commandsé 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 elcommandespacio de nombres.Y aunque
commandno puede llamar directamente a las funciones de shell, puede llamarevalcomo 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
commandpalabra 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,$OLDPWDy algunos otros.Y sí, por la determinación del alcance localmente el
$PWDy$OLDPWDlas variables y después explícitamentecding a$OLDPWDy$PWDque 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
$OPTSespecialmente 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 -$OPTSjusto antes de invocar su objetivo de ajuste. De esta manera, si define-$OPTSen la línea de comandos, puede definir las opciones de shell de su objetivo de ajuste. Cuando el objetivo regrese, lo haráset +$- -$OPTScon 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
returrnimpida 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
evalde 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:$PATHestá vacío en este punto) ,evalla 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 tresevals 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
cen 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
evalses 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
$LOCALSvariable 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:
$IFSse ha desinfectado a su valor predeterminado y solo los nombres de shell válidos lo hacen a$LOCALSmenos 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=fen 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 evitaraliasexpansiones:fuente