导读:兴许所有程序员都有命名困难症,在考虑变量、常量、方法、类、文件等命名时,总会千方百计尝试一些语义化的方式去实现。
曾经有那么一段时间,一些 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 等思路是否也如出一辙呢?
全文原创·此文为随走随记,全文思维略带感情请勿拍砖。
1
shyling 2017-08-27 20:48:56 +08:00
没遇到过
|
2
mx1700 2017-08-27 20:51:18 +08:00 via Android
你可能用的假 nodejs
|
3
xcold OP 嘿嘿 实际上我自己也碰见过,只是把一些同学遇到的问题复盘了一遍~
|
4
NemoAlex 2017-08-27 21:03:25 +08:00 via iPhone
总之如果没有特殊的目的,不要用 Windows 来直接做这些语言的开发。实在要用就开个 Linux 的虚拟机,方便多了。
|
5
Miy4mori 2017-08-27 21:08:19 +08:00 via iPhone
你估计装了某个魔改 node 在 path 里,which 一下看先,我用 windows10 cmder nvm 三个组合从没遇到这个问题。
|
6
ioc 2017-08-27 21:31:09 +08:00 via Android
我刚刚试了下,没有问题
|
8
xqin 2017-08-27 21:50:46 +08:00
@xcold 把命令打全, 或者 把你的文件名换个名字.
你的问题在于, 1. 你调用 node 没有加 .exe 2. 你的文件名叫 node.js,当你在命令行中输入 node 的时候, windows 先找到了当前目录下的 node.js, 所以直接调用 与.js 文件所关联和 WSH 来进行执行. 至于 windows 为什么会先找到 node.js 文件然后调用 WSH 来执行,而不是直接用 nodejs 来执行是因为 windows 命令行下在执行程序之前会先在当前目录中找对应的文件名+一些特定的扩展名(比如:exe,bat,cmd,js 之类的). 最简单的命令你在你自己的目录下建一个 123.bat 或者 123.cmd 的文件,然后在命令中进入 到当前目录,只输入 123, 就可以调用它. 同理你有一个 123.js 的时候,你也可以输入 123 来调用 WSH 来解析它. 正确的方法, 用 `node.exe node.js` 或者 `node 1.js` (1.js 为你的 node.js 改名之后的) |
9
xcold OP 感谢各位热心的网友~这贴不是求助帖子哈~你们说的所有的方案估计我都考虑过的~
|
10
ceoimon 2017-08-27 22:51:10 +08:00 via iPhone
虽然基本不用 CMD(WSL 很好用啊), 还是学习了。
|
11
doubleflower 2017-08-27 23:37:33 +08:00
折腾这么多还不如把 windows 弃了
|
12
syncher 2017-08-27 23:40:58 +08:00 via Android
为啥我也没遇到过?
|
13
FrankFang128 2017-08-27 23:53:31 +08:00
Windows 的坑
|
14
lslqtz 2017-08-28 04:56:58 +08:00
你的环境变量没 node 目录吧。。
|
15
lslqtz 2017-08-28 04:58:55 +08:00
node.js 安装时默认情况下是不会加到 path 的
|
16
arfaWong 2017-08-28 07:06:03 +08:00 via Android
没遇到过+ 1
|
18
autoxbc 2017-08-28 10:10:34 +08:00 via iPhone
好可惜很多人没看懂,用个伪正则说明一下
系统补全策略 (当前目录|%PATH%中的目录) node (显式指定扩展名|%PATHEXT%备选扩展名) 因为 .js 也是备选可执行扩展名 所以 node 被补全为 .\node.js 最后变成执行 .\node.js node.js 至于最后启动的是 WSH 还是文本编辑器就看个人系统的设置了 |
19
SakuraKuma 2017-08-28 10:41:18 +08:00
windows 问题,优先在当前目录找东西。
当年很多游戏都可以 hijack 也是这个原理。 用一个游戏加载的同名 dll 放在游戏目录下,会优先加载该 dll,然后进行游戏修改。 |