流云浮星

Awesome Man

Windows 环境变量那些事

Posted at — Dec 10, 2018

环境变量的查找顺序

在 Windows 上可以在命令提示符或 PowerShell 中输入 python 启动 Python 的 REPL。Windows 是如何找到 python 这个命令的呢,当然是通过 %Path% 的环境变量,因此对每个文件夹进行查找,找到最先出现的 python 可执行文件。

使用 WHERE 命令可以对环境变量中和当前目录中的可执行文件进行查找。

例如:

C:\Users\Foair>WHERE python
C:\Program Files\Python37\python.exe

所以当 Windows 查找一个可执行文件是按照环境变量中目录,和当前路径进行查找的。只要找到一个就不会继续查找了。

还有一点需要说明的就是可执行文件,在 Windows 中可执行文件不只是 .exe,Windows 默认的至少就有 .bat .cmd .js .msc .com 等文件,并不局限于 .exe 文件。

可执行文件名的扩展名可以使用 ECHO %PATHEXT% 查看。

C:\Users\Foair\Desktop>ECHO %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW

当输入一个命令的时候,比如 touch 就会去查找这些扩展名的文件,touch 可能对应 touch.exe,但也可能对应 touch.py,取决于优先级和文件存在与否。在上面的 %PATHEXT% 的环境变量中,.exe 的优先级是高于 .py 文件的,因此当两个文件都存在的时候,调用 .exe 文件的优先级是高于 .py 文件的。

同理,%Path% 环境变量也是具有优先级的,越早出现,优先级越高。当然,当搜索一个可执行文件的时候,当前目录的优先级高于%Path%,因此当前文件夹的可执行文件总是先调用。另外 %Path% 的搜索优先级高于 `%PATHEXT%

假设 D:\alias 已经放到 %Path% 环境变量下,并在 D:\alias 创建一个 xxx.cmd。另一个在 %USERPROFILE%\Desktop 下创建 xxx.batxxx.cmd。(xxx 命令需要没有被占用,且 .bat 优先级高于 .cmd。)

当在 %USERPROFILE%\Desktop 下调用 xxx 的时候,应该是调用 %USERPROFILE%\Desktop\xxx.bat

C:\ 下调用 xxx 命令,应该是调用 D:\alias\xxx.cmd

假如 %USERPROFILE%\Desktop 也加在了 %Path% 的最后,在 D:\ 调用的也是 D:\alias\xxx.cmd

其他环境变量可以使用 SET 命令进行查看。

参考

这事要从 node node.js 说起 - 前端 - 掘金

“Register” an .exe so you can run it from any command line in Windows - Stack Overflow

添加 JavaScript 文件默认为 Node 执行

在 Python 的安装程序中提供了 Python Launcher,用于将 .py 文件关联为可执行文件,简化调用过程。

而 Node.js 不提供这样的功能,.js 也被 Windows 的 WSH 占用,而 WSH 现在基本上也不会用到(得出这个结论是找了很多资料的,因为 jsc 这样的编译器都被藏得很深)。因此可以放心大胆地将 .js 文件关联到 Node。

ASSOC .js=NodeJS
FTYPE NodeJS=node %1 %*

%1 代表当前打开的文件,比如 index.js,也可以使用 %L 代替(Python Launcher 写的是 %L),根据零星的资料,这个应该表示的是完整的长路径,而 %1 是短路径。使用上,应该没有太大的差别。

还原到默认的设置,执行以下命令:

ASSOC .js=JSFile

备注

以下命令和 WSH 有关。.vbs.js 都和这两个有关。JScript 可以调用 .Net。

CScript /?
WScript /?

参考

Run .js files using node.exe on Windows 7

如何规划环境变量的设置

对于大型的应用程序,比如 TeX Live,可以将所有 .exe 文件所在的 bin 目录添加到环境变量。而经常使用的单个程序,比如 aria2,可以将 aria2c.exe 生成可执行的 .bat.cmd 文件添加到一个目录,这个目录专门用来存放这些「快捷方式」。

我将这个目录在 D:\alias,将所有可执行的 .bat 放在这个地方。并将这个目录放到环境变量中,那样就不会有其他的程序来「污染」当前的环境变量。

其实这个做法的来源是 Node.js,当全局安装一个 Node 模块的命令行程序的时候,就会创建一个同名的 .cmd 文件,当在命令行调用这个程序的时候,就会查找到这个可执行的 .cmdjs 程序得以执行。

npm i @vue/cli -g 后,会在一个目录中创建 vue.cmd,内容可能如下:

@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\node_modules\@vue\cli\bin\vue.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\node_modules\@vue\cli\bin\vue.js" %*
)

@ 的意思是不显示当前命令的输出,%* 是传入是所有参数。

vue.cmd 所在的目录存在 node.exe 时会使用该 node 引擎解析 JavaScript,并将一些参数传递给 node。如果不存在,那么就会在局部设置一个新的环境变量(只影响当前批处理,不会扩散),并且将 .js 的可执行去除,使用全局的 node 进行 JavaScript 的解析。

因此我要创建一个 aria2c.exe 的快捷方式到到 D:\alias 下,这样就不会造成其他负面影响。

aria2.bat 的内容如下:

@G:\aria2\aria2c.exe %*

这样就很灵活了。

同理,如果我想将 Course Cralwer 映射为 moocal,可以创建 moocal.batD:\alias,写下如下内容:

@G:\course-crawler\mooc.py %*

备注

%cd% 可以用在批处理和当前命令行中,而 %~dp0 只能用在批处理中。且 %cd% 是当前目录,而 %~dp0 是批处理所在目录。% 使用 %% 进行转义。

%~dp0 是对第 0 个参数,一般是可执行文件进行扩展,~ 表示扩展,d 表示驱动器,p 代表路径。

一些详细的说明可以在命令提示符下面键入 CALL /? or FOR /? 来查看。

参考

Windows 7 - Which special variables are available when writing a shell command for a context menu - Super User

Windows 脚本中 %~dp0 的含义 - huaius - ChinaUnix 博客

Microsoft Windows XP - Using batch parameters

后记

还可以将程序路径添加到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths 中,不过这样只能使用 START 命令或「运行」来启动,是不可以直接键入程序名的。

START 命令的用法:https://ss64.com/nt/start.html

一般来说 cmd 的用法很诡异,在未来应该是要被 PowerShell 完全取代的。但现在 PowerShell 的打开很慢,所以批处理还是有其存在的意义。

附一个设置工具,用来生成 xxx.cmd

Aliases for Windows command line

Rapid Environment Editor(环境变量设置工具,用处不大)

启动一个程序(也可以打开一个文件)

@ECHO OFF
start "" "C:\Program Files (x86)\Software\software.exe" %*

或者

@ECHO OFF
"C:\Program Files (x86)\Software\software.exe" %*

完整的操作步骤

MKDIR D:\aliases
SETX PATH "D:\aliases;%PATH%"

创建一个新窗口的 CMD

@ECHO OFF
START "myprogram" /D "C:\path to\" /W "myprogram.exe" %*

在当前窗口的 CMD(切换到另一个目录,然后切换回来)

@ECHO OFF
PUSHD "E:\path\"
"shortcut.exe" %*
POPD

保留当前的工作目录(如果可执行文件需要依赖,就会在当前目录查找不到依赖)

CD /D D:\aliases\
MKLINK "shortcut.exe" "E:\origin.exe"