¿Actualizar las variables de entorno de la sesión de pantalla para reflejar un nuevo inicio de sesión gráfico?

20

Uso Linux y me gusta hacer todo mi trabajo de línea de comandos dentro de una sola sesión de pantalla, para poder reiniciar mi inicio de sesión gráfico y tal sin perder mis terminales. Sin embargo, cuando salgo y vuelvo a mi sesión gráfica, esto cambia todas las variables de entorno de mi sesión, como las sesiones DBus. Esto significa que después de iniciar sesión nuevamente, mi sesión de pantalla ahora tiene las variables de entorno antiguas (e incorrectas). Entonces, cuando trato de iniciar programas gráficos desde mi sesión de pantalla, en el mejor de los casos emiten una advertencia sobre no poder conectarse al bus de sesión. En el peor de los casos, no pueden comenzar por completo.

Entonces, lo que estoy buscando es una forma de modificar las variables de entorno en una instancia de pantalla en ejecución, para que todas las ventanas de pantalla creadas posteriormente hereden las nuevas variables de entorno. ¿Hay alguna forma de hacer esto?

Ryan C. Thompson
fuente
3
¡Ajá! Solo busqué en toda la página del manual de la pantalla para encontrar esto:setenv [var [string]] Set the environment variable var to value string. If only var is specified, the user will be prompted to enter a value. If no parameters are specified, the user will be prompted for both variable and value. The environment is inherited by all subsequently forked shells.
Ryan C. Thompson,
Se puede invocar setenv usando el interruptor -X a la pantalla. Por desgracia, solo funciona en todos los depósitos bifurcados posteriormente, no en el caparazón actual.
Boris Bukh
Tenga en cuenta que byobu ahora incorpora una solución para esto tanto para screen como para tmux.
Ryan C. Thompson

Respuestas:

8

No puede iniciar un script de shell desde la screensesión ya que heredaría el entorno anterior. Sin embargo, puede usar un quince para obtener las nuevas variables de entorno en la sesión de pantalla anterior. Puede completar esa cantidad cuando comience su sesión gráfica.

#!/bin/bash
FIFO=/tmp/your_variables
[ -e $FIFO ] && cat $FIFO > /dev/null || mkfifo $FIFO

# save number of variables that follow
NVARS=2
echo $NVARS > $FIFO
echo ENV1=sth1 > $FIFO
echo ENV2=sth2 > $FIFO

Inicie ese script en segundo plano al iniciar sesión (solo terminará cuando se lean todas las variables).

Ahora puede leer desde el fifo, por ejemplo, agregue esta función a su .bashrc

update_session() {
  FIFO=/tmp/your_variables

  NVAR=$(cat $FIFO)
  for i in $(seq $NVAR); do
    export $(cat $FIFO)
  done
  #delete the pipe, or it will not work next time 
  rm $FIFO
}

para que puedas en tu screensesión anterior

update_session
Benjamin Bannier
fuente
¿no necesitaría hacer esto una vez por ventana en la sesión en ejecución para modificar el shell principal de la ventana?
quack quijote
Agradable, aunque como dice ~ quack, necesita actualizar cada shell de forma independiente.
dmckee
Correcto, debe hacer eso en cada shell en screen. AFAIK screenno expone enchufes o similares para comunicarse con sesiones en ejecución desde el exterior.
Benjamin Bannier
@dmckee pero, por supuesto, cada nueva screen sesión ya tiene las variables de entorno recientes
Benjamin Bannier
He decidido aceptar esta respuesta por ahora. Si alguna vez llego a implementar esto, lo actualizaré. Pero por ahora, es suficiente tener una sensación cálida y borrosa de saber que es teóricamente posible.
Ryan C. Thompson
2

He implementado un script para hacer esto. Puede obtenerlo aquí: https://github.com/DarwinAwardWinner/screen-sendenv

Después de ponerlo screen-sendenv.pyen su $PATH, puede usar el siguiente fragmento en su .bashrc:

VARS_TO_UPDATE="DISPLAY DBUS_SESSION_BUS_ADDRESS SESSION_MANAGER GPG_AGENT_INFO"
screen_pushenv () {
  screen-sendenv.py -t screen $VARS_TO_UPDATE
}
tmux_pushenv () {
  screen-sendenv.py -t tmux $VARS_TO_UPDATE
}
screen_pullenv () {
  tempfile=$(mktemp -q) && {
    for var in $VARS_TO_UPDATE; do
      screen sh -c "echo export $var=\$$var >> \"$tempfile\""
    done
    . "$tempfile"
    rm -f "$tempfile"
  }
}
tmux_pullenv () {
  for var in $VARS_TO_UPDATE; do
    expr="$(tmux showenv | grep "^$var=")"
    if [ -n "$expr" ]; then
      export "$expr"
    fi
  done
}

Para usarlo, solo ejecute screen_pushenvantes de ejecutar screen -rpara volver a conectar a su sesión de pantalla. Luego, después de adjuntar con screen -r, puede actualizar el entorno en sus shells existentes con screen_pullenv. Las funciones tmux logran lo mismo para tmux, otro multiplexor de terminal similar a la pantalla.

Ryan C. Thompson
fuente
Wow Ryan, eso es mucho código. ¿Qué estaba mal con la respuesta previamente aceptada (al menos fue inspiradora)?
Benjamin Bannier
1
Bueno, descubrí que la pantalla (y también tmux) tiene un comando "setenv" que establece una variable de entorno para la pantalla en sí, no el shell en la ventana actual de la pantalla. Eso significa que después de usar mi script, todas las ventanas recién creadas en esa sesión de pantalla obtendrán automáticamente el nuevo entorno, sin tener que ejecutar el script de actualización en cada una de ellas. Por supuesto, un script de actualización aún podría ser útil para actualizar los shells existentes, pero debe reescribirlo para no leerlo desde un FIFO, sino para consultar en la sesión screen / tmux los nuevos valores.
Ryan C. Thompson
Puede ver cómo extraer variables en el shell actual desde la sesión screen / tmux aquí , en las funciones screen_updatey tmux_update. Actualizaré mi respuesta con una versión independiente de byobu de estos.
Ryan C. Thompson
1
De todos modos, para responder directamente a su pregunta sobre lo que estaba mal, su respuesta no responde a la pregunta, sino que responde una pregunta relacionada. Muestra cómo actualizar las variables de entorno dentro de un shell que se ejecuta dentro de una sesión de pantalla, pero no cómo actualizar las variables de entorno en la sesión de pantalla en sí (de modo que las ventanas recién generadas hereden los nuevos valores). Lo acepté en el momento, ya que era todavía una buena solución, pero siempre tenía la intención de finalmente poner en práctica una verdadera respuesta a la pregunta que se le preguntó . Entonces, nada personal.
Ryan C. Thompson
Hola Ryan, gracias por responder. Ahora que lo mencionaste setenv, veo cómo esto es mejor. No era obvio por el código al que te vinculaste. ¡Gracias de nuevo!
Benjamin Bannier
2

Puede invocar el setenvcomando para cambiar las variables de entorno en el proceso de la pantalla de forma interactiva, utilizando: Ctrl- A+ :setenv(Tenga en cuenta el :carácter para ingresar un comando de pantalla). Se le solicitará el nombre y el valor de la variable de entorno.

Tenga en cuenta que (según otras respuestas / comentarios) esto afecta el proceso de pantalla (principal) y, por lo tanto, las sesiones de pantalla recién creadas, pero no su sesión de pantalla actual ni ninguna sesión de pantalla existente.

Puede especificar el nombre y el valor de la variable de entorno al mismo tiempo si desea: Ctrl- A+ :setenv DISPLAY :100. Establecerá la PANTALLA en ": 100" para las nuevas sesiones de pantalla.

Para eliminar una variable de entorno, puede usar 'unsetenv', por ejemplo Ctrl, A+:unsetenv DISPLAY

Señor comadreja
fuente
0

Esta es probablemente una solución más simple (usted decide). La parte importante es el alias que llama a la savedisplayfunción cada vez que screense ejecuta el comando. Los comandos no se ejecutan automáticamente, por lo tanto, se pueden poner en ~/.bashrclugar de algo muy especializado como ~/.ssh/rc.

savedisplay() {
    # Write latest bash display to a file, This is used to 
    # update running bash sessions for a "screen -r"
    echo "export DISPLAY=$DISPLAY" > ~/.XDISPLAY
    echo "export XAUTHORITY=$XAUTHORITY" >> ~/.XDISPLAY
    # This will only update the environment for new windows
    screen -X setenv DISPLAY $DISPLAY
    screen -X setenv XAUTHORITY $XAUTHORITY
}

# run this to update env variable in a running session
updatedisplay() {
    source ~/.XDISPLAY 
}

alias screen='savedisplay && screen'
wecac
fuente