【MSYS2】隐式路径风格转换
参考文档:https://www.msys2.org/docs/filesystem-paths/
路径风格
Windows系统和Unix系统有两套截然不同的文件路径风格,我们平时遇到的路径形式大致如下:
-
C:\nope
该字符串是一个合法的Windows绝对路径,代表C
盘下的nope
文件或目录。
该字符串不是合法的Unix路径。
-
C:/nope
该字符串是一个合法的Windows绝对路径,代表C
盘下的nope
文件或目录。
该字符串不是合法的Unix路径。
-
/foo
该字符串是一个合法的Windows相对路径,代表当前盘符下的foo
文件或目录(如果程序的当前工作目录在C盘,则其表示的绝对路径为C:\foo
)。
同时,该字符串也是一个合法的Unix绝对路径,代表根目录/
下的foo
文件或目录。
在日常编程中,绝大多数情况下/foo
都指代Unix绝对路径,因此我们把这种路径风格称为Unix路径风格,或称为貌似Unix的路径风格。
-
foo/bar
该字符串是一个合法的Windows相对路径,也是一个合法的Unix相对路径,都代表程序当前工作目录下的foo/
目录下的bar
文件或目录。
转换规则
Cygwin工具
如果你的可执行文件被安装到/usr/bin
这个位置,或者在安装包时不需要指定包前缀,则该包属于MSYS环境。通过这些包安装的程序被称为Cygwin工具。
举例
/usr/bin/ls
,/usr/bin/cat
,/usr/bin/bash
这些可执行文件都属于Cygwin工具。- 通过
pacman
安装的没有包前缀的包也属于Cygwin工具。如通过如下命令pacman -S vim
,pacman -S git
安装的/usr/bin/vim
与/usr/bin/git
。
Cygwin工具只保证正确解析Unix风格的路径,是否可以正确解析Windows风格的路径,取决于该Cygwin工具的内部实现。
MSYS2不会自动将Windows风格的路径转换为Unix风格
如果你提供了Windows风格的路径给某个Cygwin工具,MSYS2并不会自动将Windows风格的路径转换为Unix风格,能否正确解析该路径字符串,完全依赖于该Cygwin工具的内部实现。
举例
ls
命令对应着Cygwin工具/usr/bin/ls
。在执行ls C:/Users
命令时,MSYS2并不会自动将Windows风格的路径C:/Users
转换为Unix风格的路径/c/Users
。之所以该命令能够正确执行,是因为Cygwin工具/usr/bin/ls
在底层实现中调用了Windows系统的API,并且/usr/bin/ls
原封不动地将输入参数C:/Users
传递给了底层Windows接口。
Windows原生工具
如果你的可执行文件被安装到类似/ucrt64/bin
, /mingw64/bin
这些位置,或者在安装包时指定了包前缀,则该包属于其它环境(如UCRT64环境、MINGW64环境等)。通过这些包安装的程序被称为Windows原生工具。
此外,如果在MSYS2中直接执行Windows系统上原生安装的程序,这些“Windows系统上原生安装的程序“也算作Windows原生工具。
举例
- 通过
pacman
安装的指定了包前缀的包属于Windows原生工具。如通过如下命令pacman -S mingw-w64-ucrt-x86_64-python
,pacman -S mingw-w64-x86_64-perl
安装的/ucrt64/bin/python3
与/mingw64/bin/perl
。- 在MSYS2中使用Windows上原生安装的应用程序,这些程序也算作Windows原生工具。比如我在Windows系统上从Python官网安装了python解释器,然后在MSYS2中使用了它,那么这个python解释器也属于Windows原生工具。
Windows原生工具只保证正确解析Windows风格的路径,这些程序和你在Windows上直接安装的其它原生程序没有本质区别。
举例
- 假设我们的MSYS2安装在
C:/msys64/
目录下。- 让Windows原生工具
/ucrt64/bin/python3
执行以下脚本文件path_test.py
,脚本的含义是“打印/Users/
目录的绝对路径”。# path_test.py import os print(os.path.abspath('/Users/'))
我们已经知道,
/Users/
这种路径风格在Windows和Unix下都是合法的,但代表的含义不同。那么Windows原生工具/ucrt64/bin/python3
会将这个路径理解为哪种风格呢?
观察解释器的输出:/ucrt64/bin/python3 path_test.py # 返回 C:/Users
结果很明了,Windows原生工具
/ucrt64/bin/python3
将路径/Users/
理解为一个Windows风格的相对路径。
在MSYS2中使用这类Windows原生工具的时候,请特别小心这种情况!因为Windows原生工具只保证正确解析Windows风格的路径,如果你在脚本文件中试图使用Unix风格的绝对路径(如/tmp/
等),这些路径将会被Windows原生工具理解为Windows风格的相对路径(/tmp/
被理解为工作盘符:/tmp/
),这完全不是你想要的结果!
在特定情况下,MSYS2会自动将“貌似Unix风格的路径”转换为Windows风格
尽管Windows原生工具只保证正确解析Windows风格的路径,MSYS2为我们提供了两种“隐式路径风格转换”的情况——如果你通过以下两种方式之一
-
- Bash命令行传参
-
- Bash环境变量
提供了貌似Unix风格的路径给某个Windows原生工具,MSYS2会自动将貌似Unix风格的路径转换为Windows风格。最终,这个Windows原生工具会接收到一个“被MSYS2隐式转换后”的Windows风格路径。
举例
- 假设我们的MSYS2安装在
C:/msys64/
目录下。- 通过Bash命令行给Windows原生工具
/ucrt64/bin/python3
提供一个“貌似Unix风格的”绝对路径参数--dir=/foo
。通过返回的结果可以发现,Python接受的第二个输入参数被MSYS2自动转换为了--dir=C:/msys64/foo
。
MSYS2自动将/foo
路径中的”根目录/
“替换为了MSYS2的安装目录C:/msys64/
。/ucrt64/bin/python3 -c "import sys; print(sys.argv)" --dir=/foo # 返回 ['-c', '--dir=C:/msys64/foo']
- 通过Bash环境变量给Windows原生工具
/ucrt64/bin/python3
提供包含“貌似Unix路径”的环境变量MYVAR=/foo
。通过返回的结果可以发现,Python在读取环境变量MYVAR
值的时候,值被MSYS2自动转换为了C:/msys64/foo
。MYVAR=/foo /ucrt64/bin/python3 -c "import os; print(os.environ['MYVAR'])" # 返回 C:/msys64/foo
再次强调,MSYS2的隐式路径转换只有在以下两种情况时有效
-
- Bash命令行传参
-
- Bash环境变量
如果你在Python脚本文件里写了/foo
路径,然后让Windows原生的Python解释器去执行这个脚本,那么解释器会直接将它理解为Windows风格的相对路径盘符:/foo
,而不是MSYS2隐式转换过的MSYS2安装目录/foo
。