进程能否不管任何 shell 都运行?

进程能否不管任何 shell 都运行?

我正在尝试从操作系统进程的角度掌握 shell 和终端的概念以及它们之间的确切关系。所以我在这方面有几个问题。

  1. 健全性检查:据我所知,shell 是用户与操作系统交互的接口,即运行其他进程。尽管 shell(例如 Bash)只是另一个进程。对吗?

  2. 有没有办法运行一个不属于 shell 进程子进程的进程?

  3. 环境变量:在 bash 中,有几个脚本会在您生成 shell 时运行,例如.bashrc.bash_profile等(取决于 shell 的类型 - 交互式与非交互式、登录与非登录)。这些脚本定义了环境变量。如果有一种方法可以运行进程而不管任何 shell,那么环境变量从何而来?

答案1

健全性检查:据我所知,shell 是用户与操作系统交互的界面,即运行其他进程。

是的,但“shell”具体是指用户接口,而不是编程接口。其他程序不需要与其交互 - 它们可以直接使用相同的系统调用来创建新进程。

因此,命令行 shell 与其他程序(例如服务管理器或图形用户界面(图形 shell))处于同一级别。

尽管shell(例如Bash)只是另一个过程。

是的。在类 Unix 系统上,这是一个完全正常的、非特权进程。

有没有办法运行一个不属于 shell 进程子进程的进程?

从用户的角度来看:是的,有几种方法。

  • 大多数 shell 都有一个exec关键字,它会导致新程序代替shell(保留相同的 PID 和父级),这可能不是您的意思,但从技术上讲是您要求的。

  • 图形桌面会话通常无需调用 bash 或任何其他 shell 即可启动,这会自动应用于通过图形菜单启动的应用程序。应用程序的父进程将是负责显示菜单的任何进程(例如窗口管理器或面板)。

  • 目前流行的systemdinit 系统在启动服务时根本不使用 shell,因此您可以定义一个 .service 并启动它 - 该服务的父级将是 init 本身。它还具有允许使用 即时创建临时服务的功能systemd-run,结果相同。

从程序员的角度来看,只需使用fork()execve()系统调用即可启动新进程。(存在特定于操作系统的细节,例如 fork() 实际上可能是不同调用的包装器,但它仍然以相同的方式工作。)

事实上,即使程序想要调用 shell,它也会通过创建新的子进程并使用相同的 fork+exec 运行 /bin/sh 来实现。没有特殊的系统调用来运行 shell。(程序员在用 C 编写时可以使用 system(),在 Python 中可以使用 os.system(),但这些仍然只是 fork/exec 的便捷包装器。)

环境变量:在 bash 中,有几个脚本会在您生成 shell 时运行,例如 .bashrc、.bash_profile 等(取决于 shell 的类型 - 交互式与非交互式、登录与非登录)。这些脚本定义了环境变量。如果有一种方法可以运行进程而不管任何 shell,那么环境变量从何而来?

嗯,有时他们不会。(当尝试让图形应用程序获取环境自定义时,这是一个真正的实际问题,具体取决于特定图形环境的启动方式。)

但总体而言,环境变量不是CLI shell 独有。每个进程,无论它是如何启动的(甚至包括 init 进程),都会收到一个包含其命令行的字符串数组,以及一个包含其环境变量的字符串数组。启动子进程时,它可以指定不同的环境,也可以允许继承其自身环境的副本。

因此,当您登录时,您的 shell 已经从其父进程接收了一些初始环境变量。这些启动脚本(bashrc 等)只是方便用户自定义 shell 子进程将继承的环境变量的地方。


这个答案的许多部分也完全适用于 Windows——尽管它的图形界面有点复杂,但 CLI shell(cmd.exe 和 PowerShell)仍然是普通程序,在正常运行中根本不使用。唯一的主要区别是 Windows 有一个“CreateProcess”调用,而不是 Unix 风格的单独“fork + exec”调用。

答案2

  1. 没错。最终,shell 将执行exec系统调用,该系统调用在所有符合 POSIX 的操作系统中都可用,更普遍的是,在所有类 Unix 操作系统(包括 Linux)中都可用。其他操作系统也有类似的概念。在 Linux 上,系统exec调用最终将调用execve由内核提供的函数,该函数实际负责加载可执行文件并运行它。

  2. 是的。任何进程都可以调用exec,而不必是“shell”。例如,当您通过单击文件系统浏览器启动程序时,桌面软件就是执行调用的程序exec,没有 shell。请注意,进程将成为启动它的桌面软件的子进程。所有进程都是另一个进程的子进程,除了第一个进程,它被调用init并具有 PID 1。它负责在启动时设置操作系统并启动所有其他进程,例如后台服务和桌面登录。如今在 Linux 上,systemd通常用作init进程,但还有其他替代方案。

  3. 有几种exec( execlexecle、 ...) 的变体,它们除了要运行的程序名称外,还具有各种参数。最终,execve系统调用采用程序名称、作为命令行参数的字符串列表和作为环境变量的字符串列表。例如,当从文件系统浏览器启动软件时,环境变量可能会从文件系统浏览器本身的变量中复制,并可能由文件系统浏览器修改。这完全取决于文件系统浏览器的程序员。

进一步阅读:

相关内容