导读:兴许所有程序员都有命名困难症,在考虑变量、常量、方法、类、文件等命名时,总会千方百计尝试一些语义化的方式去实现。
曾经有那么一段时间,一些 node 初学的同学遇到了同样的问题:Hello World 跑不动!
原文首发于个人博客:这事要从 node node.js 说起
问题的起源非常简单,当我们在编写一个入门程序时,就会迅速想起那句脍炙人口的语句:
console.log('Hello World');
于是乎,顺手保存为 node.js ,紧接着尝试以node node.js
来运行该示例程序。毫无疑问,在 cmd 环境下,会遇到如下的报错:
( PS:实际上无论是 Mac、Linux 用户,亦或是 WIndows 中使用 Powershell 或其他终端环境的同学都无法与此问题完美邂逅)
此时此刻,心中一阵失落,居然连入门的示例程序都无法运行,不禁一阵瞎想:是否该放弃 node.js 了?
言归正传,细心的同学会发现,报错的源头来自Windows Script Host
,下简称WSH
,我们不难查到它是 Windows 操作系统脚本语言程序( script,即:脚本)的运行环境。
简单分析一下node node.js
这条命令,我们会很自然地认定为:执行 node.exe 程序,参数为 node.js 。
然而实际上,真正执行的程序却变成WSH
,前面执行的命令node node.js
并没有任何跟调起WSH
相关的逻辑,因此为何调起了WSH
成为了解谜的关键。
顺蔓摸瓜,由于WSH
正好是执行脚本的服务,而 js 恰恰又是脚本的一种,不妨假设node.js
这个脚本文件就是罪魁祸首。然后创建一个test.js
的副本,尝试执行它:
根据试验的结果不难猜出node node.js
命令实际执行了node.js
这个脚本文件,从而调起WSH
服务,进而出现上图的报错。
顺水推舟可确定node node.js
等价于.\node.js node.js
,即命令执行的文件完整的路径为:E:\test\node.js
。
( PS:各位看官切莫介怀''作为路径分隔符,毕竟在 cmd 下'/'担任参数分隔符的要职)
先讲讲通用的说法,无论是 * nix、OS/2、DOS 亦或是 windows,其 terminal 都可以通过一个特殊的环境变量PATH
进行“补全”(关于环境变量的详细内容本文不作介绍)。
接下来我们通过 ping 命令先做简要说明:
很明显,在任何一台正常的机器上,这条命令执行后都能得到期待的结果。此时我们可以看到该 cmd 进程下的PATH
环境变量中包含C:\WINDOWS\system32
,通过对PATH
中的元素(文件夹路径)即可将 ping 程序的路径补全为:C:\WINDOWS\system32\ping
。(在 * nix 系统下依然通用)
由于 windows 的可执行的概念和 * nix 略有不同,因此在 windows 平台下还需要对程序进行后缀名的补全。
其中在 * inx 下,只需保证文件的结构符合规范,并且拥有可执行权限,就可以执行;而在 windows 下,还需要考虑其后缀名及执行方式(实际上是一种打开方式的策略)。
E:\test>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW;.CPL
最终我们补全的程序路径为:C:\WINDOWS\system32\ping.exe
,
针对于 cmd 环境,当前目录也会作为路径补全的一部分,并且优先级最高。在当前目录下,我们创建一个ping.bat
的脚本,并填充以下内容:
@echo off
:: 输出完整的路径和文件名及后缀
echo %~dpnx0
执行结果如下图,原来的ping.exe
的动作明显被覆盖了。
我们也额外地发现 windows 的默认可执行的后缀名包含.JS
,由此可推断最初的那条node node.js
命令最终补全的程序路径为:E:\test\node.js
从 2.2.4 的结论中能显而易见的推导出命令执行的程序为node.js
脚本文件,那么它为什么是通过WSH
去执行的呢?
答案其实很明显,有个通俗易懂的概念,叫做打开方式,而 windows 的打开方式由assoc
和ftype
确定。
尝试性的跑一跑assoc
命令,发现其控制着后缀名与打开方式ftype
的关系。
assoc | findstr .js
运行结果:
.js=JSFile
.json=VisualStudio.json.14.0
.jsonld=VisualStudio.jsonld.14.0
.jsx=VisualStudio.jsx.14.0
.jsxbin=JSXBINFile
.jsxinc=JSXINCFile
不难看出.js
文件将会通过JSFile
这个打开方式去执行。
类似的,我们也可以运行一下 ftype 命令,其定义了可执行程序以及调用的参数。
ftype | findstr "JS"
运行结果:
JSEFile=C:\Windows\System32\WScript.exe "%1" %*
JSFile=C:\Windows\System32\WScript.exe "%1" %*
JSXFile="C:\Program Files (x86)\Adobe\Adobe Utilities - CS6\ExtendScript Toolkit CS6\ExtendScript Toolkit.exe" -run "%1"
其中最关键的信息为JSFile=C:\Windows\System32\WScript.exe "%1" %*
,含义是通过WScript.exe
执行 js 脚本,并将原来的参数传递过去。
最终node node.js
等价于E:\test\node.js node.js
。
node.js
了~操作系统层面通过PATH
等环境变量进行资源定位的思路实际上也被广泛应用在各种场景下,下面也举两个常见的栗子说明一下。
CommonJS 规范中通过require
去加载模块时,通过路径补全的策略(详情推荐阅读《深入浅出 Node.js 》),可以省略模块的路径,后缀名,甚至连 /index 也能自动补全。
嘿,resolve 中的 extensions、alias 等思路是否也如出一辙呢?
全文原创·此文为随走随记,全文思维略带感情请勿拍砖。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.