izabera/psist eine Bash-Implementierung, die eine Ausgabe ähnlich zups auxinnerhalb von Bash nachahmen soll, selbst in Situationen, in denen keine neuen Prozesse erstellt werden können- Die Kernbedingung ist, dass auf einer per
sshverbundenen Maschine zwar eine vertrauenswürdige bash shell vorhanden ist, aber alle anderen PIDs bereits belegt sind, sodass kein neuer Prozess erzeugt werden kann - Das README stellt diese Situation als Beispiel für eine Interviewfrage für Positionen vor, die Bash-/Linux-Kenntnisse erfordern
- Das Tool wird so beschrieben, dass es einem erlaubt, so zu tun, „als hätte man Zugriff auf ein funktionierendes
ps aux“, ohne eine vollständige Ersatzimplementierung zu garantieren - Die Aussage „funktioniert auf allen Maschinen und in allen Situationen zu 100 %“ ist offensichtlich als scherzhafte Garantie gemeint
Was macht das Projekt?
- Es handelt sich um ein Projekt, das
ps auxnur mit Bash implementiert - Der README-Titel lautet „
ps auxwritten entirely in bash without ever forking“ - Das zentrale Merkmal des Projekts ist, dass es während der Ausführung überhaupt keinen Fork verwendet
Das angenommene Szenario
- Das Beispielszenario sieht so aus
- Man ist per
sshauf einer Maschine eingeloggt - Der Nutzer befindet sich in einer vertrauten bash shell
- Aber alle anderen PIDs sind bereits belegt, sodass sich überhaupt kein neuer Prozess erzeugen lässt
- Man ist per
- Das README erklärt, dass unter solchen Bedingungen eine
ps aux-ähnliche Funktion nützlich sein kann
Erwartbarer Umfang und Caveat
- Das Tool wird als etwas vorgestellt, mit dem man „kinda sorta pretend“ kann, man hätte ein funktionierendes
ps aux - Die README-Formulierung „funktioniert perfekt in allen Situationen auf 100 % der Maschinen, garantiert“ ist als überzogener Humor gemeint
- Der Kern der Beschreibung ist daher weniger vollständige Kompatibilität als vielmehr die Nachahmung von
ps auxallein mit Bash in einer extremen Umgebung, in der keine neuen Prozesse erstellt werden können
1 Kommentare
Meinungen auf Hacker News
Der Witz, dass das schwierigste Problem der Informatik am Ende doch Ausrichtung ist, trifft einen Nerv.
Ich habe unzählige Male Funktionen zur Spaltenausrichtung in verschiedenen Sprachen geschrieben, und jedes Mal war es schmerzhaft. Im Kopf wirkt es so simpel wie: „Bestimme die maximale Länge jeder Spalte und füge Leerzeichen bis zum nächsten Vielfachen der Tabulatorgröße ein.“
Selbst mit Pythons f-Strings und Padding-Funktionen wird der Code schnell kompliziert und schwer lesbar; während ich ein Beispiel für einen Kommentar neu schrieb, habe ich sogar mehrere Bugs behoben — so furchtbar ist das.
Für einen so häufigen Anwendungsfall sollte es doch selbstverständlich eine Library geben; ehrlich gesagt überrascht es mich, dass das nicht in der Standardbibliothek enthalten ist.
Dabei werden aus
descriptioneines Datenbank-Cursors Spaltenbreiten und Namen entnommen, daraus Trennlinien und Formatstrings erzeugt und anschließend die Zeilen ausgegeben. Ich weiß nicht, ob ich dabei einen gravierenden Bug übersehen habe, aber es wirkt nicht wie ein besonders schwieriges Problem.zip(*table)die Tabelle nach Spalten dreht, die maximale Länge jeder Spalte bestimmt und dann mitf"{r:<{w}}"ausgerichtet ausgibt.Das Beispielergebnis wird dann eine Tabelle mit passenden Spaltenbreiten, etwa
agony | kick | pump.Werte enthalten Leerzeichen, sind mit Leerzeichen gepaddet, manchmal ist die Ausrichtung verschoben und Spalten laufen über.
Es wäre wohl für alle besser, wenn man sich einfach darauf einigt, keine spaltenausgerichteten Daten zu verwenden, sondern ein einfacheres, menschenlesbares Format.
Wenn ich per SSH auf einer Maschine bin, die Bash-Shell noch lebt, aber alle PIDs aufgebraucht sind und keine neuen Prozesse mehr erzeugt werden können, würde ich das Dateisystem
/proc/[pid]/durchsuchen, um herauszufinden, welcher Prozess den PID-Raum erschöpft.killin Bash ist ein Shell-Builtin und muss daher im Gegensatz zu/bin/killkeinen neuen Prozess forken.Wenn man den Elternprozess findet, der die Kinder erzeugt, die die PIDs aufbrauchen, kann man ihn stoppen und die Kontrolle über das System zurückgewinnen.
Dieses Skript parst ebenfalls
/procund ist ziemlich sauber, weil es weder Pipes noch$(...)-Substitutionen verwendet, die eine neue Bash-Subshell erzeugen könnten.Damit kann man die nötigen POSIX-Funktionen aufrufen, ohne einen separaten Befehl auszuführen, und das kam gut an.
Das System nach einem Reboot wiederherzustellen kann schneller sein, als in einer eingeschränkten Umgebung den Elternprozess zu finden und zu töten; wenn die PIDs ausgegangen sind, ist wahrscheinlich auch anderes bereits in einem schlechten Zustand.
ps(){ (cd /proc;for i in [0-9]*;do echo $i: $(tr '\0' ' ' < $i/cmdline);done); }/proc/[pid]/nachzusehen, welcher Prozess den PID-Raum erschöpft, ist richtig; den Kommentaren im Quellcode zufolge hatte man anfangs aber gehofft, dass allein/proc/*/statusausreichen würde, doch Werte wie die CPU-Auslastung lassen sich dort nicht bekommen.[[ $cmdline ]] && exec {cmdline}>&-undexec {cmdline}< "$dir"/cmdline || continuefunktionieren.2011 hatte ich ein Vorstellungsgespräch für eine SRE-Rolle bei einem recht großen US-Tech-Unternehmen; damals hörte ich den Begriff SRE zum ersten Mal.
Das Unternehmen arbeitete an einer browserbasierten Alternative zu MS Office, und nach dem Telefonscreening musste ich während eines Anrufs mit dem Interviewer live in deren Dokumenteneditor programmieren.
Weil ich mich in der Selbsteinschätzung bei
shell scriptingundLinuxhoch eingestuft hatte, bekam ich die Aufgabe, in Bash einen Ersatz fürnetstatzu bauen. Damals wusste ich aber nicht, wo und wie Socket-Informationen unter/proc/liegen, und entschied schnell, dass ich das nicht hinbekommen würde.Stattdessen schlug ich vor, abgespeckte Versionen von
psundfuserzu bauen, und meine Lösung in diesem furchtbaren browserbasierten Textverarbeitungsprogramm wurde akzeptiert, sodass ich es bis zum Onsite-Interview schaffte.Rückblickend könnte das hypothetische Szenario, das diese Übung motivierte, stärker in der Realität verwurzelt gewesen sein, als ich dachte.
Ich würde auch dort anfangen.
Ich habe früher zum Spaß eine interaktive Website gebaut, auf der man eine Situation erkunden kann, in der man per SSH eingeloggt ist, aber keine neuen Prozesse erstellen kann: https://oops.cmdchallenge.com
"echo *"listet nicht alle Dateien in einem Verzeichnis auf.Man muss
"echo .* *"verwenden.Ich wollte mir die Listen mit
"View Solutions"für andere Stufen ansehen, um zu sehen, welche anderen Ansätze möglich gewesen wären.Izabera ist einer der Könner in #bash@libera.
Von solchen Leuten habe ich seit den alten freenode-Zeiten in den letzten zehn Jahren wirklich viel gelernt.
Das ist ziemlich sauberes Bash.
Meiner Erfahrung nach ist Bash-Code oft schlecht geschrieben und ineffizient; dieser Code wirkt wie ein gutes Gegenbeispiel.
Was macht man, wenn man in einer verlässlichen POSIX-Shell ohne Bash-Unterstützung landet?
Dieses Bash-Skript ist nicht POSIX-kompatibel.
Dieses Skript läuft nicht unter Bash 3.2, funktioniert aber mit Bash 4.2.
Unter Bash 3.2 erscheint der Fehler
printf: '(': invalid format character; die Beispielumgebung istbash-3.2-33.el5_11.4.0.1.Ein besserer Einsatzzweck wäre wohl, auf Systemen ohne installiertes procps eine Prozessliste anzuzeigen.
Passt schon.
Mit Bash kann man auch Listener und Clients bauen.
Für die Praxis würde ich es nicht empfehlen.