Mejorando un poco la respuesta de @ takeccho ... Comprobaciones y algunos silbidos. En primer lugar, el entorno de origen se limpia a través del env -i
, que es una medida de seguridad, pero que podría no desearse en algunos casos. En segundo lugar, a través de set -a
, todas las variables establecidas en el archivo se "exportan" desde el shell y, por lo tanto, se importan a ruby. Esto es útil para simular/anular el comportamiento que se encuentra en los archivos de entorno utilizados con los scripts init y los archivos systemd env.
def ShSource(filename)
# Inspired by user takeccho at http://stackoverflow.com/a/26381374/3849157
# Sources sh-script or env file and imports resulting environment
fail(ArgumentError,"File #{filename} invalid or doesn't exist.") \
unless File.exist?(filename)
_newhashstr=`env -i sh -c 'set -a;source #{filename} && ruby -e "p ENV"'`
fail(ArgumentError,"Failure to parse or process #{filename} environment")\
unless _newhashstr.match(/^\{("[^"]+"=>".*?",\s*)*("[^"]+"=>".*?")\}$/)
_newhash=eval(_newhashstr)
%w[ SHLVL PWD _ ].each{|k|_newhash.delete(k) }
_newhash.each{|k,v| ENV[k]=v } # ENV does not have #merge!
end
Teoría de funcionamiento: Cuando rubí emite el objeto ENV usando p
, lo hace de una manera que el rubí puede leer de nuevo en como un objeto. Entonces usamos el shell para obtener el archivo objetivo, y ruby (en un subconjunto) para dar salida al entorno en esa forma serializable. Luego capturamos la salida de Ruby y eval
dentro de nuestro proceso Ruby. Claramente esto no está exento de riesgos, por lo tanto, para mitigar el riesgo, (1) validamos el nombre de archivo que se transfiere y (2) validamos usando una expresión regular que lo que obtenemos de ruby-subshell es, de hecho, una cadena de trozos serializable. Una vez que estamos seguros de eso, hacemos el eval
que crea un nuevo hash. Luego fusionamos "manualmente" el hash con ENV
, que es un Object
y no un Hash
normal. Si fuera un Hash, podríamos haber usado el método #merge!
.
EDITAR: sh -a
cosas exportadas como PATH
. También debemos eliminar SHLVL
y PWD
antes del hash-merge.
¿Qué obtienes si cambias tu script a esto? #!/Usr/bin/env ruby pone ENV ['HAPPYTIMES'] – Henry
es una buena cosa para tener acceso a las funciones de tipo sistema operativo como la configuración del entorno de los idiomas. Python tiene os.environ, ¿hay un módulo similar en Ruby que en python? cf http://stackoverflow.com/questions/4906977/python-environment-variables & http://docs.python.org/2/library/os.html – bootload
posible duplicado de [Shell out from ruby al establecer una variable de entorno ] (http://stackoverflow.com/questions/8301294/shell-out-from-ruby-while-setting-an-environment-variable) – durron597