Debuggen von Umgebungsvariablen unter Linux

Es kommt häufig vor, dass Sie an den Computer kommen und vor einer Woche eine Art Skript finden, das unter dem Systembenutzer ausgeführt wird. Wer hat es ins Leben gerufen? Wo kann man nach dieser run.php suchen? Oder Sie fügen / etc / crontab einen Eintrag hinzu, und das Skript stürzt dort mit dem Fehler "Befehl nicht gefunden" ab. Warum? Und was machen?

Ich habe die Antworten auf diese Fragen.



Umgebungsvariablen


In fast allen modernen Betriebssystemen haben Prozesse Umgebungsvariablen. Technisch gesehen handelt es sich um eine Sammlung benannter Zeichenfolgen. Wenn ein Unterprozess gestartet wird, erbt er automatisch eine Kopie der Umgebung des übergeordneten Elements.

Unter anderem gibt es die Variable PATH, die die Pfade für die Suche nach ausführbaren Dateien angibt, die Variable HOME, die auf das Ausgangsverzeichnis des Benutzers verweist, die Variablen, die für die Spracheinstellungen des Benutzers verantwortlich sind, und viele andere.

Es gibt viele Übersichten, die die Bedeutung dieser Variablen beschreiben, aber es gibt praktisch keine Artikel zur Untersuchung von Problemen. Füllen Sie diese Lücke.

Wer hat den Prozess gestartet?


Daher haben wir vor einer Woche ein Skript gefunden, das unter dem Systembenutzer ausgeführt wird. Wer hat es ins Leben gerufen? Warum? Vielleicht haben sie ihn einfach vergessen? Möglicherweise könnten 10-15 Personen es starten. Sie werden nicht alle interviewen. Wie finde ich heraus, wer es war? Und wo liegt diese run.php?

$ ps x | grep run.php 10684 ? Ss 472:25 /local/php/bin/php run.php 

Prozessumgebungsvariablen und die Sudo-Funktion helfen dabei. Es gibt eine solche PWD-Variable, in der die Shell das aktuelle Arbeitsverzeichnis speichert. Dieser Wert speichert tatsächlich Informationen über das aktuelle Verzeichnis zum Zeitpunkt der Ausführung des Befehls. Außerdem hinterlässt das Dienstprogramm sudo standardmäßig Informationen in der Prozessumgebungsvariablen darüber, von welchem ​​Benutzer es gestartet wurde.

Umgebungsvariablen (und vieles mehr) für jeden laufenden Prozess finden Sie in / proc. Voila:

 $ cat /proc/10684/environ | tr '\0' '\n' | grep SUDO_USER SUDO_USER=alexxz $ cat /proc/10684/environ | tr '\0' '\n' | grep PWD PWD=/home/etlmaster 

Ähm, ich habe es selbst gestartet. Nun, wem passiert das nicht?

Im Allgemeinen können Sie mit einer so einfachen Methode in einfachen Situationen Informationen über den Prozess finden, die im Allgemeinen nicht verfügbar sind.

Das Skript funktioniert über die Befehlszeile, jedoch nicht über cron


Einer der Fälle, in denen Sie über Umgebungsvariablen nachdenken müssen, besteht darin, dass ein zu / etc / crontab hinzugefügtes Skript mit einem Fehler abstürzt. Sie gehen über SSH zum Server, führen den Befehl aus, alles scheint so zu funktionieren, wie es sollte. Und wenn es automatisch gestartet wird, wird so etwas wie "hive: Befehl nicht gefunden" angezeigt.

Im Allgemeinen empfiehlt es sich, den vollständigen Pfad zu ausführbaren Befehlen zu schreiben. Dies ist jedoch nicht immer möglich. In solchen Fällen steigen die Entwickler so weit wie möglich aus. Jemand fügt den gewünschten Pfad in PATH als Teil des Teams in crontab hinzu. Erfahrene verpacken ihr Kommando in bash -l. Und die Krähenbomben, die durch bittere Erfahrung gelehrt werden, vergessen immer noch nicht, sich zu scharen. Alles ist so: gemacht, zur Überwachung hinzugefügt und vergessen.

Nach solchen Manipulationen verbleibt ein Sediment in der Seele eines echten Ingenieurs. Ja, das Problem ist gelöst. Aber ich habe nicht verstanden, was los war! Wie ist ein Ansatz besser als ein anderer? Wo werden all diese Einstellungen gespeichert und von wem werden sie geändert?

Vergleichen wir die Umgebungsvariablen, über die der Prozess verfügt, wenn er über die Krone gestartet wird, und die Umgebungsvariablen, die wir in der Befehlszeile haben. Wir protokollieren die Ausgabe des Befehls env von der Krone und unserer aktuellen Umgebung:

 $ echo "* * * * * env > ~/crontab.env" | crontab; sleep 60; echo "" | crontab; $ env > my.env 

Schauen Sie, was in der PATH-Variablen enthalten ist:

 > grep ^PATH= crontab.env my.env Crontab.env: PATH=/usr/bin:/bin My.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/local/hadoop/bin:/usr/local/bin:/usr/bin:/bin 



Mama Mia! Also da unter der Krone nur das Minimum! Natürlich müssen Sie die normalen Umgebungsvariablen laden.

Mal sehen, wie die Umgebung aussehen wird, wenn wir bash -l hinzufügen:

 $ echo "* * * * * bash -l env > ~/crontab.env" | crontab; sleep 60; echo "" | crontab; alexxz@bi1.mlan:~> grep ^PATH= crontab.env my.env Crontab.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/usr/local/bin:/usr/bin:/bin My.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/local/hadoop/bin:/usr/local/bin:/usr/bin:/bin 

Der Unterschied ist nicht so auffällig. Alle Pfade werden dargestellt. Einige in einer anderen Reihenfolge, andere werden wiederholt, aber das ist schon viel besser als es war. Der Rest der Variablen ist ebenfalls gut abgestimmt. Es gibt natürlich einen kleinen Unterschied im Gebietsschema, in den Variablen von SSH, aber dies sollte den Betrieb des Skripts nicht mehr dramatisch beeinflussen.

Jetzt ist klar, warum bash -l in crontab-Einträgen benötigt wird. Und vergessen Sie natürlich nicht die Herde.

Debug-Initialisierung von Anmeldeskripten


Das Problem scheint gelöst zu sein, alles von der Krone funktioniert. Aber wie kommt es, dass einige Pfade in der PATH-Variablen dupliziert werden? Es gibt also eine Art Chaos im Server-Setup. Versuchen wir es herauszufinden.

Wir öffnen einige Mans, um die Umgebung zu initialisieren, wir lesen vor, welche Skripte und in welcher Reihenfolge ausgeführt werden, mit Begeisterung laufen wir ihnen durch die Augen - und nach ein paar Minuten kommt ein Gefühl der Verzweiflung. Einige endlose Bedingungen für einige Sonderfälle von Architekturen, Terminals und unglaublich wichtigen Farbeinstellungen für den Befehl ls. Schmerz, Verzweiflung, Hass! Wir interessieren uns für eine verdammt variable PATH!

In der Tat ist alles etwas einfacher. Treffen:

 env -i bash -x -l -c 'echo 123' > login.log 2>&1 

Was macht dieses Team? Erstellt einen neuen Bash-Prozess mit einer makellosen Umgebung und gibt an, dass Initialisierungsskripte ausgeführt und alle Details in der Datei login.log gesichert werden müssen. Jetzt haben wir die Möglichkeit, nicht alle Skripte in unserem Kopf auszuführen, sondern einfach zu lesen, was, wo und wann es ausgeführt wurde und woher diese oder jene Umgebungseinstellung stammt.

Ich werde nicht im Detail analysieren, wie das resultierende Protokoll zu lesen ist. Dort ist alles fast trivial. Ich erwähne nur, dass ein Treffer von / etc / profile und zwei von /etc/bash.bashrc kam. Ja, irgendwo waren sie zu schlau, wenn sie Pakete in einem Pappet aufstellten. Naja, nichts, es stört mich nicht zu arbeiten.

Aber jetzt weiß und kann ich!

PS In sehr schwierigen Fällen und um alles zu verstehen, können Sie den Befehl in Klammern setzen:

  strace -f env -i bash -x -l -c 'echo 123' > login.log 2>&1 

Source: https://habr.com/ru/post/de465021/


All Articles