Im vorherigen Artikel haben wir eine Shell-Hauptschleife erstellt, die Befehlseingabe aufgeteilt und den Befehl über fork
und exec
ausgeführt. In diesem Teil werden wir uns mit den verbleibenden Problemen befassen. Erstens kann der Befehl cd test_dir2
unser aktuelles Verzeichnis nicht ändern. Zweitens können wir die Shell immer noch nicht ordnungsgemäß verlassen.
„cd test_dir2
kann unser aktuelles Verzeichnis nicht ändern“ Dieser Satz ist richtig, aber in gewissem Sinne auch falsch. Es ist in dem Sinne richtig, dass wir uns nach der Ausführung des Befehls immer noch im selben Verzeichnis befinden. Das Verzeichnis wurde jedoch tatsächlich geändert, jedoch im untergeordneten Prozess.
Denken Sie daran, dass wir einen untergeordneten Prozess gegabelt und dann den Befehl ausgeführt haben. Der Prozess zur Ausführung des Befehls fand nicht im übergeordneten Prozess statt. Das Ergebnis ist, dass wir nur das aktuelle Verzeichnis des untergeordneten Prozesses ändern, nicht das Verzeichnis des übergeordneten Prozesses.
Dann wird der untergeordnete Prozess beendet, während der übergeordnete Prozess im intakten Verzeichnis weiterläuft.
Daher müssen solche Befehle, die sich auf die Shell selbst beziehen, integrierte Befehle sein. Es muss im Shell-Prozess und nicht im Forking ausgeführt werden.
Beginnen wir mit dem Befehl cd
.
Wir erstellen zunächst ein builtins
-Verzeichnis. Jeder integrierte Befehl wird in diesem Verzeichnis abgelegt.
yosh_project |-- yosh |-- builtins | |-- __init__.py | |-- cd.py |-- __init__.py |-- shell.py
In cd.py
implementieren wir unseren eigenen os.chdir
-Befehl, indem wir den Systemaufruf cd
verwenden.
import os from yosh.constants import * def cd(args): os.chdir(args[0]) return SHELL_STATUS_RUN
Beachten Sie, dass wir den Betriebsstatus der Shell von der integrierten Funktion zurückgeben. Um Konstanten weiterhin im Projekt verwenden zu können, haben wir sie nach yosh/constants.py
verschoben.
yosh_project |-- yosh |-- builtins | |-- __init__.py | |-- cd.py |-- __init__.py |-- constants.py |-- shell.py
In constants.py
haben wir hier alle Zustandskonstanten eingefügt.
SHELL_STATUS_STOP = 0 SHELL_STATUS_RUN = 1
Jetzt ist unser eingebautes cd
fertig. Ändern wir shell.py
, um diese integrierten Funktionen zu verarbeiten.
... ### 导入常量 from yosh.constants import * ### 使用哈希映射来存储内建的函数名及其引用 built_in_cmds = {} def tokenize(string): return shlex.split(string) def execute(cmd_tokens): ### 从元组中分拆命令名称与参数 cmd_name = cmd_tokens[0] cmd_args = cmd_tokens[1:] ### 如果该命令是一个内建命令,使用参数调用该函数 if cmd_name in built_in_cmds: return built_in_cmds[cmd_name](cmd_args) ...
Wir verwenden eine Python-Wörterbuchvariable built_in_cmds
als Hash-Map, um unsere integrierten Funktionen zu speichern. Wir extrahieren den Namen und die Parameter des Befehls in der Funktion execute
. Befindet sich der Befehl in unserer Hash-Map, wird die entsprechende integrierte Funktion aufgerufen.
(Tipp: built_in_cmds[cmd_name]
gibt eine Funktionsreferenz zurück, die direkt mit Argumenten aufgerufen werden kann.)
Wir sind fast bereit, die integrierte Funktion cd
zu verwenden. Der letzte Schritt besteht darin, die Funktion cd
zur Zuordnung built_in_cmds
hinzuzufügen.
... ### 导入所有内建函数引用 from yosh.builtins import * ... ### 注册内建函数到内建命令的哈希映射中 def register_command(name, func): built_in_cmds[name] = func ### 在此注册所有的内建命令 def init(): register_command("cd", cd) def main(): ###在开始主循环之前初始化 shell init() shell_loop()
Wir definieren die Funktion register_command
, um unserer integrierten Befehls-Hash-Map eine integrierte Funktion hinzuzufügen. Als nächstes definieren wir die Funktion init
und registrieren die integrierte Funktion cd
hier.
Achten Sie auf diese Zeile register_command("cd", cd)
. Der erste Parameter ist der Name des Befehls. Der zweite Parameter ist eine Funktionsreferenz. Damit der zweite Parameter cd
auf die Funktionsreferenz yosh/builtins/cd.py
in cd
verweisen kann, müssen wir die folgende Codezeile in die Datei yosh/builtins/__init__.py
einfügen.
from yosh.builtins.cd import *
Wenn wir also in yosh/shell.py
yosh.builtins
aus *
importieren, können wir die yosh.builtins
-Funktionsreferenz erhalten, die über cd
importiert wurde.
Wir haben den Code bereit. Versuchen wir, unsere Shell yosh
als Modul im selben Verzeichnis wie python -m yosh.shell
auszuführen.
Jetzt ändert der Befehl cd
korrekt unser Shell-Verzeichnis, während nicht integrierte Befehle weiterhin funktionieren. sehr gut!
Das letzte Stück ist endlich da: elegant aussteigen.
Wir benötigen eine Funktion, die den Shell-Status in SHELL_STATUS_STOP
ändern kann. Auf diese Weise kann die Shell-Schleife auf natürliche Weise enden und die Shell erreicht das Ende und verlässt sie.
ist dasselbe wie cd
. Wenn wir die Funktion exit
im untergeordneten Prozess verzweigen und ausführen, hat dies keine Auswirkungen auf den übergeordneten Prozess. Daher muss die Funktion exit
eine in die Shell integrierte Funktion sein.
Beginnen wir hier: Erstellen Sie eine neue Datei mit dem Namen builtins
im Verzeichnis exit.py
.
yosh_project |-- yosh |-- builtins | |-- __init__.py | |-- cd.py | |-- exit.py |-- __init__.py |-- constants.py |-- shell.py
exit.py
definiert eine exit
-Funktion, die nur einen Status zurückgibt, der die Hauptschleife verlassen kann.
from yosh.constants import * def exit(args): return SHELL_STATUS_STOP
Dann importieren wir die yosh/builtins/__init__.py
-Funktionsreferenz, die sich in der exit
-Datei befindet.
from yosh.builtins.cd import * from yosh.builtins.exit import *
Zuletzt registrieren wir den Befehl shell.py
in der Funktion init()
. exit
... ### 在此注册所有的内建命令 def init(): register_command("cd", cd) register_command("exit", exit) ...
Versuchen Sie, python -m yosh.shell
auszuführen. Jetzt können Sie exit
eingeben, um das Programm ordnungsgemäß zu beenden.
Ich hoffe, dass Ihnen die Erstellung genauso viel Spaß gemacht hat wie mir yosh
(Ihrunserem >ellen) Prozess. Aber meine Version von steckt noch in den Kinderschuhen. Ich habe mich nicht mit einigen Eckfällen befasst, die die Shell zum Absturz bringen würden. Es gibt viele integrierte Befehle, die ich nicht behandelt habe. Um die Leistung zu verbessern, können einige nicht integrierte Befehle auch als integrierte Befehle implementiert werden (um Zeit für die Erstellung neuer Prozesse zu sparen). Gleichzeitig sind zahlreiche Features noch nicht implementiert. Ich habe den Quellcode unter https://github.com/supasate/yosh bereitgestellt. Bitte zögern Sie nicht, es zu forken und auszuprobieren. yosh
Jetzt ist es an der Zeit, eine Hülle zu erstellen, die wirklich zu Ihnen passt.
Viel Spaß beim Codieren!
Das obige ist der detaillierte Inhalt vonSo erstellen Sie Ihre eigene Shell mit Python (Teil 2). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!