Aktualisieren der Umgebungsvariablen der Bildschirmsitzung, um die neue grafische Anmeldung widerzuspiegeln?

18

Ich verwende Linux und erledige meine gesamte Befehlszeilenarbeit gerne in einer einzigen Bildschirmsitzung, damit ich meine grafische Anmeldung und dergleichen neu starten kann, ohne meine Terminals zu verlieren. Beim Abmelden und erneuten Anmelden an meiner Grafiksitzung werden jedoch alle Sitzungsumgebungsvariablen geändert, z. B. DBus-Sitzungen. Dies bedeutet, dass meine Bildschirmsitzung nach dem erneuten Anmelden die alten (und falschen) Umgebungsvariablen enthält. Wenn ich jetzt versuche, grafische Programme von meiner Bildschirmsitzung aus zu starten, wird bestenfalls eine Warnung ausgegeben, dass keine Verbindung zum Sitzungsbus hergestellt werden kann. Im schlimmsten Fall können sie nicht vollständig starten.

Ich suche also nach einer Möglichkeit, Umgebungsvariablen in einer laufenden Instanz des Bildschirms zu ändern, sodass alle anschließend erstellten Bildschirmfenster die neuen Umgebungsvariablen übernehmen. Gibt es eine Möglichkeit, dies zu tun?

Ryan Thompson
quelle
2
Aha! Ich habe gerade die gesamte Bildschirm-Manpage durchgeblättert, um Folgendes zu finden: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 Thompson
Man kann setenv mit -X switch to screen aufrufen. Leider funktioniert es nur auf allen später gegabelten Shells, nicht auf der aktuellen Shell.
Boris Bukh
Beachten Sie, dass byobu jetzt eine Lösung dafür für screen und tmux enthält.
Ryan Thompson

Antworten:

8

Sie können ein Shell-Skript nicht von der screenSitzung aus starten, da es die alte Umgebung erben würde. Sie können jedoch ein Fifo verwenden, um die neuen Umgebungsvariablen in die alte Bildschirmsitzung zu übernehmen. Sie können dieses FIFO füllen, wenn Sie Ihre grafische Sitzung starten.

#!/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

Starten Sie dieses Skript beim Anmelden im Hintergrund (es wird erst beendet, wenn alle Variablen daraus gelesen wurden).

Jetzt können Sie aus dem Fifo lesen, zB diese Funktion zu Ihrem hinzufügen .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
}

damit Sie in Ihrer alten screenSitzung können

update_session
Benjamin Bannier
quelle
Müssten Sie dies nicht einmal pro Fenster in der laufenden Sitzung tun, um die Haupt-Shell des Fensters zu ändern?
Quack Quijote
Schön, aber wie ~ quack sagt, müssen Sie jede Shell einzeln aktualisieren.
dmckee
Richtig, das musst du in jeder Shell in machen screen. AFAIK screenstellt keine Sockets oder ähnliches zur Verfügung, um mit laufenden Sitzungen von außen zu kommunizieren.
Benjamin Bannier
@dmckee, aber natürlich hat jede neue screen Sitzung bereits die aktuellen Umgebungsvariablen
Benjamin Bannier
Ich habe beschlossen, diese Antwort erst einmal anzunehmen. Wenn ich jemals dazu komme, dies tatsächlich umzusetzen, werde ich aktualisieren. Aber fürs Erste ist es genug, nur ein warmes, verschwommenes Gefühl zu haben, zu wissen, dass es theoretisch möglich ist.
Ryan Thompson
2

Ich habe ein Skript dafür implementiert. Sie können es hier herunterladen : https://github.com/DarwinAwardWinner/screen-sendenv

Nach dem Einfügen screen-sendenv.pyin Ihr $PATHkönnen Sie das folgende Snippet in Ihrem .bashrc verwenden:

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
}

Um es zu verwenden, führen screen_pushenvSie es einfach aus, bevor Sie erneut screen -reine Verbindung zu Ihrer Bildschirmsitzung herstellen. Nach dem Anhängen mit screen -rkönnen Sie die Umgebung in Ihren vorhandenen Shells mit aktualisieren screen_pullenv. Die tmux-Funktionen bewirken dasselbe für tmux, einen anderen Terminal-Multiplexer ähnlich wie screen.

Ryan Thompson
quelle
Wow Ryan, das ist viel Code. Was war falsch an der zuvor akzeptierten Antwort (zumindest inspirierend)?
Benjamin Bannier
1
Nun, ich habe herausgefunden, dass screen (und auch tmux) einen "setenv" -Befehl haben, der eine Umgebungsvariable für screen selbst festlegt, nicht die Shell im aktuellen Fenster von screen. Das bedeutet, dass nach der Verwendung meines Skripts alle neu erstellten Fenster in dieser Bildschirmsitzung automatisch die neue Umgebung erhalten, ohne dass das Aktualisierungsskript in jedem von ihnen ausgeführt werden muss. Natürlich kann ein Update-Skript weiterhin nützlich sein, um vorhandene Shells zu aktualisieren. Sie müssen es jedoch neu schreiben, um nicht aus einem FIFO zu lesen, sondern um die neuen Werte in der screen / tmux-Sitzung selbst abzufragen.
Ryan Thompson
Sie können hier in den Funktionen screen_updateund sehen, wie Sie Variablen aus der screen / tmux-Sitzung in die aktuelle Shell ziehen tmux_update. Ich werde meine Antwort mit einer byobu-unabhängigen Version aktualisieren.
Ryan Thompson
1
Um Ihre Frage nach dem, was falsch war, direkt zu beantworten, beantwortet Ihre Antwort die Frage nicht ganz, sondern vielmehr eine verwandte Frage. Sie zeigen, wie Sie Umgebungsvariablen in einer Shell aktualisieren, die in einer Bildschirmsitzung ausgeführt wird, aber nicht, wie Sie Umgebungsvariablen in der Bildschirmsitzung selbst aktualisieren (so dass neu erzeugte Fenster die neuen Werte übernehmen). Ich nahm es an der Zeit , weil es immer noch eine gute Lösung war, aber ich hatte immer gedacht , um schließlich eine wirkliche Antwort auf meine Frage zu implementieren als gefragt . Also nichts persönliches.
Ryan Thompson
Hey Ryan, danke für die Antwort. Nun, da du es erwähnt hast, setenvsehe ich, wie es besser ist. Aus dem Code, mit dem Sie verlinkt haben, war dies nicht ersichtlich. Danke noch einmal!
Benjamin Bannier
0

Dies ist wahrscheinlich eine einfachere Lösung (Sie entscheiden). Der wichtige Teil ist der Alias, der die savedisplayFunktion jedes Mal aufruft, wenn ein screenBefehl ausgeführt wird. Die Befehle werden nicht automatisch ausgeführt und können daher ~/.bashrcanstelle von sehr speziellen Befehlen eingegeben werden ~/.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
quelle