不能在中文目录右键打开 Cygwin 的解决方法
Cygwin 是一个 Windows 下的 Linux POSIX 模拟器,通过它我们可以直接运行一个 Linux 终端,非常好用。
网络上关于如何添加一个 “在当前目录打开 Cygwin” 的右键菜单的教程有很多,但是这些方法都有一个问题,那就是不能在中文目录下正常工作,于是研究了一番,修复了这个问题。
探索
既然英文路径可以但中文不行,我最先想到的是使用 Cygwin 自带的 base64 命令,将 encode(path) 后的非中文字符串传给 Cygwin 之后,再 decode 得到包含中文的路径。然而不行,正确的 base64 传递到 Cygwin 之后 decode 却是乱码。
问题的原因很容易想到,那就是编码的问题。经过几次输出中间变量后验证了这个猜想:Windows 采用的是 GB2312 编码,而 Cygwin 采用的是 UTF-8. Windows 将当前路径作为参数传递给 Cygwin 主程序时,Cygwin 不能正确读取路径。
解决
修改 Windows 或者 Cygwin 的默认编码肯定是下下之策。解决该问题最终还是绕不开编码转换。我最终的思路为:
- 右键点击后,Windows 将当前路径作为参数 1 传递给 run_by_right_click.bat 入口程序
- run_by_right_click.bat 将路径写入 chere.path 文件(GB2312 编码),并运行 Cygwin
- Cygwin 运行后,将 chere.path 转换为 UTF-8 编码,读取后 cd
我的 Cygwin 安装目录为 C:\cygwin64,Shell 为 ZSH,如果你使用的是 Bash,有的地方与我的不同。具体步骤如下:
step1. 创建右键按钮
导入注册表文件 cygwin.reg:
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Directory\Background\shell\cygwin64_bash] @="打开 Cygwin 终端" "icon"="C:\cygwin64\Cygwin.ico" [HKEY_CLASSES_ROOT\Directory\Background\shell\cygwin64_bash\command] @="C:\cygwin64\run_by_right_click.bat \"%V\""
step2. 编写入口程序
我们的入口程序 C:\cygwin64\run_by_right_click.bat
@echo off SET dir=%1 REM 双引号删除 SET dir=%dir:"=% C: chdir C:\cygwin64 rem del /Q chere.path set /p="%dir%">chere.path bin\zsh.exe -li
bat 代码是真的难写。。。写这段代码我便踩了无数的坑。
step3. 完成目录跳转
在 Cygwin 内编写 ~/.zshrc,在末尾添加目录跳转命令:
if [ -e /chere.path ];then /usr/bin/enca -L zh_CN -x utf-8 /chere.path CPWD=/usr/bin/cat /chere.path
rm /chere.path cd/bin/cygpath "$CPWD"
fi
这里用到了 enca 用于自动编码转换,所以需要在 Cygwin 包管理器中安装这个软件。
over! 现在便可以在中文文件夹中右键打开 Cygwin 了。
为啥我要用 Cygwin
最后最后。你可能会说,为啥都新世纪了,你还在用 Cygwin 这种… 模拟器?原生 Linux/ 虚拟机 不好用嘛?WSL 不香吗?甚至 Powershell 不也不错?
那我还真觉得 Cygwin 秒杀上述所有的方案。首先,我只是想在 Windows 上安装一个代替 cmd 的 Shell 环境用于日常操作,并不需要高性能什么的,所以原生 Linux 系统、虚拟机、Docker 就不是解决同一个问题的东西。
至于 Powershell,虽说是比 cmd 好多了,但毕竟是另一套语法和体系,我不想学它也对它不感兴趣。Bash+GNU tools 那才是世界通用法则。ZSH 作为日常使用的终端也确实美观好用!
而 WSL 这东西确实很吸引人,性能比 Cygwin 强太多,几乎就是原生系统。然而!WSL 运行于内核态,与 Windows 平级,就算有文件系统的映射,WSL 也并不能直接当作 Windows 的 Shell 来使用的。看下面的图你就知道我在说啥了。
图中,npm 和 git 是我在 Windows 中安装的 exe 包,而 ssh、tail、md5sum 是 Cygwin 中提供的 Linux 命令,直接相互调用无压力,这才是 Windows 中我想要的 Shell 的样子。可是 WSL 是不能这么做的,两个系统是隔开的。