$ PATH中的查找如何在后台运行?


8

网络上有太多文章/资源可以教人们如何设置环境变量,PATH以便他们可以使用javapython等的简写代替命令行界面中的绝对路径。

我很想知道的是,当我们键入命令并按回车键时,背后什么(类似于在浏览器中键入URL时发生的情况)。

这是我的猜测:

  1. 读取命令(解析/预处理标准输入以获取正确的参数$@
  2. 命令查询
  3. 命令执行(程序已启动,消耗内存,stdout / stderr到shell)
  4. 重新渲染通过相关环境变量(例如仿真器$PS#$PROMPT等等)

我最想弄清楚的部分是命令查找。显然,$PATHs被某些后台函数使用,并用:/ ;分隔为分隔符,那么发生了什么?我们是否使用哈希表(键:文件的基名,值:文件的绝对目录名)将二进制文件存储在这些PATH或其他挂钩下?

注意:我最初认为它是哈希表,因为我可以[ -z hash [command] ]用来检查当前环境中是否有可用的命令,但是当我使用时hash | grep python,在which python按预期方式工作时,我从输出中什么也没得到。(我认为该机制可能是特定于外壳的,但我想对此有更多的了解。)

Answers:


11

您怀疑,确切的行为取决于外壳,但是POSIX指定了基线功能级别。

标准shell命令语言(大多数shell都实现了父集)的命令搜索和执行有很多情况,但是我们暂时只对PATH使用where的情况感兴趣。在这种情况下:

如XBD环境变量中所述,应使用PATH环境变量来搜索命令

如果搜索成功:

[...]

shell在单独的实用程序环境中执行该实用程序,其等效于调用path参数设置为搜索结果路径名的execl()函数[...]

在不成功的情况下,执行失败,并返回127的退出代码和错误消息。

这种行为execvp尤其与功能一致。所有exec*功能都接受要运行的程序的文件名,一系列参数(将是argv程序的参数)以及一组环境变量。对于使用PATH查找的版本,POSIX定义了

参数文件用于构建标识新过程映像文件的路径名,该文件的路径前缀是通过搜索作为环境变量PATH传递的目录而获得的。


PATH行为在其他地方定义为:

该变量应表示某些功能和实用程序在搜索仅由文件名知道的可执行文件时应用的路径前缀的序列。前缀应由<colon>(':')分隔。当非零长度前缀应用于此文件名时,如果前缀未以结束,则应在前缀和文件名之间插入<slash>。零长度前缀是旧功能,用于指示当前工作目录。它以两个相邻的字符(“ ::”)的形式出现,在列表的其余部分之前显示为首字母<colon>,或在列表的其余部分之后显示为结尾的<colon>。严格符合标准的应用程序应使用实际的路径名(例如。)来表示PATH中的当前工作目录。应从头到尾搜索列表,将文件名应用于每个前缀,直到找到具有指定名称和适当执行权限的可执行文件。如果要查找的路径名包含<slash>,则不应通过路径前缀进行搜索。如果路径名以<slash>开头,则解析指定的路径(请参阅“ 路径名解析”)。如果未设置PATH或将其设置为null,则路径搜索是实现定义的。

有点密集,所以总结一下:

  1. 如果程序名称中带有/(斜杠,U + 002F SOLIDUS),则按常规方式将其视为路径,然后跳过此过程的其余部分。对于shell,从技术上讲不会出现这种情况(因为shell规则已经处理过了)。
  2. 的值PATH在每个冒号处分为几部分,然后从左到右处理每个分量。作为特殊的(历史的)情况,非空变量的空组件被视为.(当前目录)。
  3. 对于每个组件,程序名称都以连接的形式附加到末尾/,并检查该名称下文件的存在,如果确实存在,则还要检查有效的执行(+ x)​​权限。如果这些检查中的任何一个失败,则过程继续进行到下一个组件。否则,命令将解析到该路径,并完成搜索。
  4. 如果组件用完了,搜索将失败。
  5. 如果中没有任何内容PATH,或者不存在任何内容,请执行您想要的任何操作。

实际的shell将具有内置命令,这些命令可在此查找之前找到,并且通常还具有别名和功能。那些不互动PATHPOSIX围绕这些行为定义了一些行为,您的shell可能还有更多行为。


尽管可以依靠exec*它为您完成大部分操作,但实际上,shell可能会自行实现此查找,特别是出于缓存目的,但是空缓存行为应相似。壳在这里具有相当宽的自由度,在极端情况下的行为也有细微不同。

如您所见,Bash 使用哈希表来记住以前看到的命令的完整路径,并且可以使用hash函数访问该表。第一次运行命令时,它会进行搜索,当找到结果时,它将被添加到表中,因此下次下次尝试时不必费神。

另一方面,在zsh中,PATH通常在shell启动时搜索完整内容。查找表中会预先填充所有发现的命令名称,因此通常不需要运行时查找(除非添加了新命令)。您可能会在尝试使用Tab键完成以前不存在的命令时注意到这种情况。

非常轻量级的shell(例如dash)倾向于将尽可能多的行为委派给系统库,而不必费心记住过去的命令路径。


非常感谢您提供如此详细的说明,它确实提供了深刻的见解。您PATH之间的比较bashzsh可以帮助我解决困惑!
Xlee
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.