쉘(bash, csh 등)이 내부적으로 어떻게 작동하는지 알고 싶습니다. 그래서 호기심을 충족시키기 위해 Python을 사용하여 yosh(Your Own Shell)이라는 쉘을 구현해봤습니다. 이 글에서 소개한 개념은 다른 프로그래밍 언어에도 적용될 수 있습니다.
(팁: 이 블로그 게시물에 사용된 소스 코드는 여기에서 찾을 수 있으며 코드는 MIT 라이센스에 따라 릴리스됩니다. Mac OS X 10.11.5에서 Python 2.7.10 및 3.4.3으로 테스트했습니다. . Linux 및 Windows의 Cygwin과 같은 다른 Unix 계열 환경에서 실행되어야 합니다.
시작해 보겠습니다.
0단계: 프로젝트 구조
이 프로젝트에서는 다음과 같은 프로젝트 구조를 사용했습니다.
yosh_project |-- yosh |-- __init__.py |-- shell.py
yosh_project
는 프로젝트 루트 디렉터리입니다. 간단히 이름을 yosh
으로 지정할 수도 있습니다.
yosh
은 패키지 디렉터리이고, __init__.py
는 패키지와 동일한 디렉터리 이름을 가진 패키지로 만들 수 있습니다(파이썬으로 작성하지 않는 경우 무시해도 됩니다.)
shell.py
은 기본 스크립트 파일입니다.
1단계: 셸 루프
셸을 시작하면 명령 프롬프트가 표시되고 명령 입력을 기다립니다. 입력된 명령을 수신하고 실행한 후(문서 뒷부분에서 자세히 설명) 쉘이 여기로 돌아와서 다음 명령을 기다리는 루프를 반복합니다.
shell.py
에서는 다음과 같이 shell_loop() 함수를 호출하는 간단한 기본 함수로 시작합니다.
def shell_loop(): # Start the loop here def main(): shell_loop() if __name__ == "__main__": main()
그런 다음 shell_loop()
에서 루프 여부에 대한 지침을 확인합니다. 계속하거나 중지하려면 상태 플래그를 사용합니다. 루프가 시작될 때 쉘은 명령 프롬프트를 표시하고 명령 입력이 읽힐 때까지 기다립니다.
import sys SHELL_STATUS_RUN = 1 SHELL_STATUS_STOP = 0 def shell_loop(): status = SHELL_STATUS_RUN while status == SHELL_STATUS_RUN: ### 显示命令提示符 sys.stdout.write('> ') sys.stdout.flush() ### 读取命令输入 cmd = sys.stdin.readline()
이후에는 명령 입력을 토큰화하고 실행합니다(tokenize
및 execute
기능을 구현하려고 합니다).
따라서 shell_loop()는 다음과 같습니다.
import sys SHELL_STATUS_RUN = 1 SHELL_STATUS_STOP = 0 def shell_loop(): status = SHELL_STATUS_RUN while status == SHELL_STATUS_RUN: ### 显示命令提示符 sys.stdout.write('> ') sys.stdout.flush() ### 读取命令输入 cmd = sys.stdin.readline() ### 切分命令输入 cmd_tokens = tokenize(cmd) ### 执行该命令并获取新的状态 status = execute(cmd_tokens)
이것이 전체 쉘 루프입니다. python shell.py
을 사용하여 셸을 시작하면 명령 프롬프트가 표시됩니다. 그러나 명령을 입력하고 Enter 키를 누르면 아직 tokenize
함수를 정의하지 않았기 때문에 오류가 발생합니다.
쉘을 종료하려면 Ctrl-C를 입력해 보세요. 나중에 쉘을 정상적으로 종료하는 방법을 설명하겠습니다.
2단계: 명령 토큰화
사용자가 셸에 명령을 입력하고 Enter 키를 누르면 명령은 명령 이름과 해당 매개변수 문자열을 포함하는 긴 문자가 됩니다. 따라서 문자열을 분할해야 합니다(문자열을 여러 튜플로 분할).
얼핏 보면 단순해 보입니다. cmd.split()
을 사용하여 입력을 공백으로 구분할 수 있습니다. ls -a my_folder
과 같은 명령에 작동합니다. 명령을 목록 ['ls', '-a', 'my_folder']
으로 분할하여 쉽게 처리할 수 있기 때문입니다.
그러나 echo "<span class="wp_keywordlink">Hello World</span>"
또는 echo 'Hello World'
과 같이 매개변수가 작은따옴표나 큰따옴표로 묶인 상황도 있습니다. cmd.spilt를 사용하면 2개의 태그 목록 ['echo', '"Hello', 'World"']
대신 3개의 태그 목록 ['echo', 'Hello World']
을 얻게 됩니다.
다행히도 Python은 마법처럼 명령을 분할하는 데 도움이 되는 shlex
이라는 라이브러리를 제공합니다. (팁: 정규 표현식을 사용할 수도 있지만 이 기사의 초점은 아닙니다.)
import sys import shlex ... def tokenize(string): return shlex.split(string) ...
그런 다음 이러한 튜플을 실행 프로세스로 보냅니다.
3단계: 실행
이것은 쉘의 핵심이자 흥미로운 부분입니다. 쉘이 mkdir test_dir
을 실행하면 정확히 무슨 일이 발생하나요? (팁: mkdir
은 test_dir
라는 디렉터리를 생성하는 데 사용되는 test_dir
매개변수가 있는 실행 프로그램입니다.)
execvp
은 이 단계에 필요한 첫 번째 기능입니다. execvp
의 기능을 설명하기 전에 실제로 작동하는 모습을 살펴보겠습니다.
import os ... def execute(cmd_tokens): ### 执行命令 os.execvp(cmd_tokens[0], cmd_tokens) ### 返回状态以告知在 shell_loop 中等待下一个命令 return SHELL_STATUS_RUN ...
쉘을 다시 실행하고 mkdir test_dir
명령을 입력한 후 Enter를 누르세요.
Enter 키를 누른 후 문제는 쉘이 다음 명령을 기다리지 않고 직접 종료된다는 것입니다. 그러나 디렉터리가 올바르게 만들어졌습니다.
그럼 execvp
은 실제로 무슨 일을 하는 걸까요?
execvp
是系统调用 exec
的一个变体。第一个参数是程序名字。v
表示第二个参数是一个程序参数列表(参数数量可变)。p
表示将会使用环境变量 PATH
搜索给定的程序名字。在我们上一次的尝试中,它将会基于我们的 PATH
环境变量查找mkdir
程序。
(还有其他 exec
变体,比如 execv、execvpe、execl、execlp、execlpe;你可以 google 它们获取更多的信息。)
exec
会用即将运行的新进程替换调用进程的当前内存。在我们的例子中,我们的 shell 进程内存会被替换为 mkdir
程序。接着,mkdir
成为主进程并创建 test_dir
目录。最后该进程退出。
这里的重点在于我们的 shell 进程已经被 mkdir
进程所替换。这就是我们的 shell 消失且不会等待下一条命令的原因。
因此,我们需要其他的系统调用来解决问题:fork
。
fork
会分配新的内存并拷贝当前进程到一个新的进程。我们称这个新的进程为子进程,调用者进程为父进程。然后,子进程内存会被替换为被执行的程序。因此,我们的 shell,也就是父进程,可以免受内存替换的危险。
让我们看看修改的代码。
... def execute(cmd_tokens): ### 分叉一个子 shell 进程 ### 如果当前进程是子进程,其 `pid` 被设置为 `0` ### 否则当前进程是父进程的话,`pid` 的值 ### 是其子进程的进程 ID。 pid = os.fork() if pid == 0: ### 子进程 ### 用被 exec 调用的程序替换该子进程 os.execvp(cmd_tokens[0], cmd_tokens) elif pid > 0: ### 父进程 while True: ### 等待其子进程的响应状态(以进程 ID 来查找) wpid, status = os.waitpid(pid, 0) ### 当其子进程正常退出时 ### 或者其被信号中断时,结束等待状态 if os.WIFEXITED(status) or os.WIFSIGNALED(status): break ### 返回状态以告知在 shell_loop 中等待下一个命令 return SHELL_STATUS_RUN ...
当我们的父进程调用 os.fork()
时,你可以想象所有的源代码被拷贝到了新的子进程。此时此刻,父进程和子进程看到的是相同的代码,且并行运行着。
如果运行的代码属于子进程,pid
将为 0
。否则,如果运行的代码属于父进程,pid
将会是子进程的进程 id。
当 os.execvp
在子进程中被调用时,你可以想象子进程的所有源代码被替换为正被调用程序的代码。然而父进程的代码不会被改变。
当父进程完成等待子进程退出或终止时,它会返回一个状态,指示继续 shell 循环。
运行
现在,你可以尝试运行我们的 shell 并输入 mkdir test_dir2
。它应该可以正确执行。我们的主 shell 进程仍然存在并等待下一条命令。尝试执行 ls
,你可以看到已创建的目录。
但是,这里仍有一些问题。
第一,尝试执行 cd test_dir2
,接着执行 ls
。它应该会进入到一个空的 test_dir2
目录。然而,你将会看到目录并没有变为 test_dir2
。
第二,我们仍然没有办法优雅地退出我们的 shell。
我们将会在下篇解决诸如此类的问题。
위 내용은 Python으로 자신만의 셸을 만드는 방법(1부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

Python은 게임 및 GUI 개발에서 탁월합니다. 1) 게임 개발은 Pygame을 사용하여 드로잉, 오디오 및 기타 기능을 제공하며 2D 게임을 만드는 데 적합합니다. 2) GUI 개발은 Tkinter 또는 PYQT를 선택할 수 있습니다. Tkinter는 간단하고 사용하기 쉽고 PYQT는 풍부한 기능을 가지고 있으며 전문 개발에 적합합니다.

Python은 데이터 과학, 웹 개발 및 자동화 작업에 적합한 반면 C는 시스템 프로그래밍, 게임 개발 및 임베디드 시스템에 적합합니다. Python은 단순성과 강력한 생태계로 유명하며 C는 고성능 및 기본 제어 기능으로 유명합니다.

2 시간 이내에 Python의 기본 프로그래밍 개념과 기술을 배울 수 있습니다. 1. 변수 및 데이터 유형을 배우기, 2. 마스터 제어 흐름 (조건부 명세서 및 루프), 3. 기능의 정의 및 사용을 이해하십시오. 4. 간단한 예제 및 코드 스 니펫을 통해 Python 프로그래밍을 신속하게 시작하십시오.

Python은 웹 개발, 데이터 과학, 기계 학습, 자동화 및 스크립팅 분야에서 널리 사용됩니다. 1) 웹 개발에서 Django 및 Flask 프레임 워크는 개발 프로세스를 단순화합니다. 2) 데이터 과학 및 기계 학습 분야에서 Numpy, Pandas, Scikit-Learn 및 Tensorflow 라이브러리는 강력한 지원을 제공합니다. 3) 자동화 및 스크립팅 측면에서 Python은 자동화 된 테스트 및 시스템 관리와 같은 작업에 적합합니다.

2 시간 이내에 파이썬의 기본 사항을 배울 수 있습니다. 1. 변수 및 데이터 유형을 배우십시오. 이를 통해 간단한 파이썬 프로그램 작성을 시작하는 데 도움이됩니다.

10 시간 이내에 컴퓨터 초보자 프로그래밍 기본 사항을 가르치는 방법은 무엇입니까? 컴퓨터 초보자에게 프로그래밍 지식을 가르치는 데 10 시간 밖에 걸리지 않는다면 무엇을 가르치기로 선택 하시겠습니까?

Fiddlerevery Where를 사용할 때 Man-in-the-Middle Reading에 Fiddlereverywhere를 사용할 때 감지되는 방법 ...

Python 3.6에 피클 파일로드 3.6 환경 보고서 오류 : modulenotfounderror : nomodulename ...


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경
