Kenntnis des Umfangs und der Lebensdauer von Umgebungsvariablen in Shell-Skripten

992
Decent Dabbler

Ich ziehe mir die Haare aus dem Kopf und versuche, Shell-Scripting zu verstehen und Umgebungsvariablen zu übergeben, und was nicht.

Ich versuche, ein PHP-Skript von TextWrangler auszuführen, das wiederum ein neues PHP-Skript mit Terminal öffnet. (TextWrangler ist ein Texteditor, der die Möglichkeit hat, Skripts auszuführen, die sich in einem bestimmten Ordner befinden, um beispielsweise das aktuell aktive Dokument zu bearbeiten).

Das erste Skript befindet sich in:

/Users/<username>/Library/Application Support/TextWrangler/Scripts/ 

... und sein Inhalt ist:

#!/usr/bin/php <?php var_dump( $_SERVER ); chdir( __DIR__ ); $file = realpath( '../Unix Support/test.php' ); exec( sprintf( 'open -a Terminal "%s" &', $file ) ); exit( 0 ); ?> 

Der zweite ist in:

/Users/<username>/Library/Application Support/TextWrangler/Unix Support/ 

... und sein Inhalt ist:

#!/usr/bin/php <?php var_dump( $_SERVER ); exit( 0 ); ?> 

TextWrangler übergibt einige Umgebungsvariablen an das erste Skript (auf das ich zugreifen kann $_SERVER), und sie sind wie erwartet. Zum Beispiel der korrekte Dateipfad zum aktuellen Dokument, das in TextWrangler aktiv ist.

Beim ersten Ausführen des Skripts werden die Umgebungsvariablen automatisch korrekt an das zweite Skript (das ich mit dem öffne exec()) übergeben.

Nun kommt der frustrierende Teil: Wenn ich das aktive Dokument in TextWrangler umstelle und das Skript erneut ausführe, erhält das erste Skript erneut die korrekten Umgebungsvariablen von TextWrangler, das zweite Skript verfügt jedoch weiterhin über die alten Umgebungsvariablen, es sei denn, ich hatte zuvor Terminal getötet. Natürlich erinnert sich die Terminalsitzung irgendwie an die ersten Umgebungsvariablen und möchte nicht aktualisieren.

Aber abgesehen von diesem sehr grundlegenden Verständnis habe ich nicht die geringste Ahnung, wie Umgebungsvariablen funktionieren, welche Möglichkeiten sie haben usw. Kann jemand also erklären, wie ich es so machen kann (wenn möglich, um damit zu beginnen) das zweite Skript erhält auch wieder die korrekten Umgebungsvariablen, ohne jedes Mal Terminal beenden zu müssen?

Ich habe bereits vor dem Aufruf versucht, Umgebungsvariablen explizit im ersten Skript festzulegen exec():

foreach( $_SERVER as $key => $value ) { putenv( "$key=$value" ); } exec( ... etc. ); 

Ich habe versucht, die Umgebungsvariablen am Ende sowohl in den ersten als auch in den zweiten Skripts zu löschen:

foreach( $_SERVER as $key => $value ) { putenv( "$key" ); } 

Aber nichts funktioniert wie erwartet. Alle neuen Erkenntnisse wurden sehr geschätzt.

bearbeiten:

In der Zwischenzeit habe ich eine alternative, aber unbefriedigende Lösung gefunden: Wenn ich mit rufe open -n -a Terminal ...(beachten Sie das hinzugefügte -nArgument) exec(), startet es jedes Mal eine neue Terminalsitzung mit den korrekten Umgebungsvariablen. Dies öffnet jedoch jedes Mal eine völlig neue Terminal-Instanz.

aktualisieren:

Ich habe den Prozess etwas vereinfacht, indem ich jetzt nur ein Skript anstelle von zwei verwendeten, indem ich die Umgebungsvariable teste SHLVL. Ich habe es jetzt auch geschafft, auf eine neue Terminal-Instanz zu verzichten, indem ich eine temporäre Datei verwende, wie Scott es auch vorgeschlagen hat. Daraus ergab sich folgendes. Aber ich finde es immer noch nicht sehr elegant.

$shellLevel = getenv( 'SHLVL' ); if( 1 == $shellLevel ) { file_put_contents( 'env.dat', serialize( $_SERVER ) ); exec( sprintf( 'open -a Terminal "%s" &', __FILE__ ) ); exit( 0 ); } else { $_SERVER = unserialize( file_get_contents( 'env.dat' ) ); unlink( 'env.dat' ); foreach( $_SERVER as $key => $value ) { putenv( "$key=$value" ); } } 

Also, ich bin noch offen für andere Vorschläge (abgesehen von der CLI und den von Scott bereits vorgeschlagenen Vorschlägen für Dateien). Es sei denn natürlich, es ist einfach nicht möglich (Scott schien das schon zu sagen).

1

1 Antwort auf die Frage

1
Scott

Haben Sie schon einmal Microsoft Office (Word, Excel und PowerPoint) verwendet? Haben Sie jemals zwei Dokumente / Arbeitsmappen / Präsentationen gleichzeitig geöffnet? Ist Ihnen aufgefallen, dass Sie normalerweise nur einen einzigen Vorgang des entsprechenden Werkzeugs erhalten, obwohl Sie zwei Fenster haben? Es ist ziemlich klar, dass das, oder etwas ziemlich ähnliches, bei Terminal geschieht. Die zweite openAnforderung wird von dem Prozess bearbeitet, der von der ersten erstellt wurde open, und sie wird erledigt, ohne einen neuen Prozess zu erstellen. Ich schätze, opendass der Prozess bereits existiert und sendet einfach eine Nachricht an ihn, anstatt einen neuen Prozess zu erstellen oder ähnliches.

Was Ihre andere Frage betrifft: Umgebungsvariablen werden vom übergeordneten Prozess an den untergeordneten Prozess übergeben (dh, wenn ein neuer Prozess erstellt wird fork), und bleiben bei execAufrufen erhalten. Sie gehen also die Prozesshierarchie durch, bis ein Prozess eine Variable beendet oder explizit ändert. Es sieht also so aus, als würde die erste openUrsache ein forkund eine execvon Terminal verursachen, wodurch die Umgebung übergeben wird, während die zweite opennur eine Nachricht an den vorhandenen Prozess sendet, um ../Unix Support/test.phperneut ausgeführt zu werden, und die Umgebung wird nicht übergeben. Sie scheinen die einzigen Möglichkeiten gefunden zu haben, um die gewünschte Funktionalität in der Umgebung zu implementieren. Erzwingen Sie jedes Mal die Erstellung eines neuen Prozesses. Andere Ansätze würden die Weitergabe der erforderlichen Daten auf andere Weise einschließen, z. B. die Befehlszeile oder eine Datei.

Scott, danke. Ihr letzter Vorschlag ist das, was ich in der Zwischenzeit auch tatsächlich gemacht habe. Ich vereinfachte die Dinge, indem ich jetzt nur ein Skript verwendete, indem ich eine übergebene Umgebungsvariable namens "SHLVL" testete, um zu sehen, ob das Skript das übergeordnete oder untergeordnete Element ist, und tatsächlich die Umgebung in einer temporären Datei speichert, wenn es sich um das übergeordnete und lesende Objekt handelt `putenv ()` -ing ihnen, wenn es das untergeordnete Skript ist. Aber es ist nicht sehr elegant. Sind Sie sicher, dass es keine elegantere Methode gibt, die Umgebungsvariablen für dieselbe Terminalsitzung außer cli oder einer Datei zu aktualisieren? Decent Dabbler vor 10 Jahren 0