10 个实验搞懂命令提示符

简介: 10 个实验搞懂命令提示符

前言

相信,很多小伙伴儿都在命令提示符中执行过 ipconfig 查看 ip 信息。我们还可以执行 ping ipping 对应的 ip 地址,执行 notepad 启动记事本,执行 explorer 启动文件管理器……

但是,你好奇过背后的运作机制吗?为什么输入几个简单的几个字母就能启动外部程序,本文试图通过一系列实验来挖掘其背后的运作机制。

如果你对下面的问题有很明确的答案,本文不是为你准备的。如果有模糊,拿不准的地方,请耐心读完。如果觉得有用,请帮忙点个在看,拜谢。

Five Questions

1、在命令提示符里输入 notepad,是哪个位置的记事本被启动了?跟什么有关?

2、如果同一个目录下有两个名为 bcn 的文件,一个是 bcn.com, 一个是 bcn.exe。在命令提示符中输入 bcn 会执行哪个?受什么影响?

3、你知道怎么让自己的程序可以直接在命令提示符中被启动吗?像执行 ipconfig 那样。

4、如果 PATH 环境变量是空的,会有什么问题?

5、如果 PATHEXT 变量是空的,会有什么问题?

PATH 实验

实验1:在命令提示符中输入一个不存在的命令(比如,bcn),使用 process monitor 观察整个过程。


如我们所料,找不到。结果如下图:

can-not-find-bcn

在观察 process monitor 捕获的日志之前,我们先查看当前命令提示符的当前路径( Current Directory)和 PATH 环境变量的值。

current directory的值

PATH环境变量的值

下图是使用 process monitor 捕获的事件,已过滤无关信息。

procmon-filter-event-bcn

红色高亮部分是当前路径相关的事件,黄白相间的部分是 PATH 环境变量相关的事件。

从此可以比较有信心的猜测:在命令提示符中输入命令会先在当前路径下查找,再到 PATH 环境变量指定的路径依次查找。

实验2: 添加一个不存在的路径到 PATH 环境变量中,再次观察整个过程。


:: 更新 PATH 环境变量
set PATH=%PATH%d:\not_existed_folder
:: 执行命令
bcn

当前路径没变,而对应的 PATH 已经多了一条 d:\not_existed_folder,如下图:

path-with-invalid-folder

下图是使用 process monitor 捕获的相关事件(已过滤无关事件)。跟上面的实验对比,发现只多了黄色高亮部分。

procmon-filter-event-with-not_existed_folder.png

注意对比上图中黄色和红色部分。红色部分对应的路径是存在的,所以有三条记录。黄色部分对应的路径是不存在的,只有一条记录。可以双击某条记录,查看对应的调用栈。相信查看过调用栈后,你会和我一样,对 Operation 这一列有一个新的认识。

callstack

实验3:bcn.exe 放到当前路径( C:\Users\bcn\Desktop)下,执行 bcn


start-bcn-on-current-folder

从上图可知,启动的是 C:\Users\bcn\Desktop\bcn.exe,因为在当前路径下就找到了对应的程序,所以并没有到 PATH 环境变量指示的路径中查找。

实验4: 删除 C:\Users\bcn\Desktop\bcn.exe,把 bcn.exe 放到 PATH 环境变量中的 c:\windows\ 下,再次执行 bcn


start-bcn-on-windows-folder

从上图可知,启动的是 C:\Windows\bcn.exe,在当前路径下没找到,然后依次到 PATH 环境变量指示的路径中查找,在c:\windows\ 下找到了对应的程序。

实验5: 清空 PATH 环境变量,在命令提示符中输入 ipconfig,看看是否能正常运行。


start-ipconfig-with-empty-path

结论:

通过以上几个实验,我们知道了在命令提示符中执行一个命令时的查找顺序是:当前路径,PATH 环境变量中指定的路径(按出现顺序进行查找)。

PATHEXT 实验

相信有细心的小伙伴儿发现了,在上面的 实验3实验4 中,会先查找 bcn.COM,没找到才继续查找的 bcn.exe。为什么是这种行为呢?跟什么有关呢?我们看下 PATHEXT环境变量的值,如下图:

pathext

我们发现 .COM 出现在 .EXE 之前,是不是这个原因呢?让我们做实验来验证。

实验6: 观察 PATHEXT 是否会影响查找结果。


调整 PATHEXT 的值为 .BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.EXE;.COM,如果查找了前面的几个后缀,而没查找 .COM,说明 PATHEXT 会影响查找结果。

set PATHEXT=.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.EXE;.COM
bcn

process monitor 捕获的事件验证了我们的猜测。截图:

pathext-search-order

实验7: 观察 PATHEXT 时的行为。


清空 PATHEXT,再执行 bcn

set PATHEXT=
bcn

process monitor 捕获相关事件如下图:

excute-with-empty-pathext

有点意外,原本以为会执行失败。看来如果 PATHEXT 是空,会使用默认的 PATHEXT,默认的 PATHEXT 是什么呢?

实验8: 观察默认的PATHEXT


重命名 bcn.exebcn.xyz(很重要),然后执行下面的命令:

set PATHEXT=
bcn

process monitor 捕获相关事件如下图:

default-pathext

在我的系统(win10 1903)中,当 PATHEXT 为空时,默认搜索的扩展名是 .COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC;。其它系统可能有不同的行为,感兴趣的小伙伴儿请自行实验。

实验9: 当前目录下同时存在 bcn.combcn.exe 会执行哪个?(通过上面的实验,结论很明显了)


分别执行下面两组命令,观察对比结果:

set PATHEXT=.COM;.EXE
bcn
set PATHEXT=.EXE;.COM
bcn

procmon 捕获的两次查找过程对比图,黄色是设置 .COM 优先的结果,红色是设置 .EXE 优先的结果。

compare-load-order

从结果可以进一步确定,优先查找 PATHEXT 中先出现的后缀名。

实验10:观察直接执行 bcn.exe 观察查找过程。


run-with-extension.png

如果命令中带后缀,那么查找的时候不会依赖 PATHEXT ,会直接执行给定的命令。

实验代码

如果你也想自己动手实验。可以新建一个工程,并粘贴下面的代码,编译生成测试程序。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "stdlib.h"

int main(int argc, char* argv[])
{
    char exe_path[MAX_PATH] = { 0 };
    ::GetModuleFileNameA(NULL, exe_path, MAX_PATH);
    printf("%s\n", exe_path);
    system("pause");
    return 0;
}

总结

相信通过上面一系列的实验,我们对命令提示符如何执行一个外部命令有了深刻的认识。对 PATHPATHEXT 这两个环境变量的作用,简单总结如下:

  1. PATH 决定了外部命令所在位置的查找顺序,PATHEXT 决定了外部命令的扩展名查找顺序。
  2. 当我们在命令提示符中输入一个命令时,会先到当前路径(Current Directory)中查找,如果找不到,才会到环境变量 PATH 指示的路径中查找。
  3. 如果输入的命令不带后缀,那么会根据 PATHEXT 指示的后缀顺序依次拼接成完整名称再查找。
  4. 如果输入的命令带后缀,不会根据 PATHEXT 中的后缀查找。
  5. 如果我们想让自己的程序也能直接通过命令提示符启动,我们可以把程序所在路径添加到 PATH 环境变量中,位置越靠前,越有可能被执行。
  6. 如果 PATHEXT 为空,那么会使用默认的 PATHEXT,我机器上的值是 .COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC;
相关文章
|
6月前
|
Linux Windows
Linux指令的运行基本原理
Linux指令的运行基本原理
44 0
|
Shell Linux
Linux操作系统实验七 Shell编程之循环程序编程(下)
Linux操作系统实验七 Shell编程之循环程序编程(下)
169 0
|
Shell Linux
Linux操作系统实验七 Shell编程之循环程序编程(中)
Linux操作系统实验七 Shell编程之循环程序编程(中)
130 0
|
6月前
|
网络协议 应用服务中间件 Apache
LINUX环境小实验
1.搭建DHCP服务器(IP:192.168.100.253静态IP网卡vmnet1) 2.搭建DNS(通过DHCP服务器分到指定的IP:192.168.100.252) 3.搭建网站服务(通过DHCP服务器分到指定的IP:192.168.100.251并且设置Apache:www.apache.com监听端口80 页面文档目录 /web/apache/ 、设置NGINX:www.nginx.com 监听端口81 页面文档目录 /web/nginx 、设置Tomcat:www.tmacat.com 端口8080 )
59 0
LINUX环境小实验
|
IDE Linux 程序员
Linux操作系统实验十二 Linux编程技术应用(上)
Linux操作系统实验十二 Linux编程技术应用
123 0
Linux操作系统实验十二 Linux编程技术应用(上)
|
运维 Prometheus Cloud Native
Linux操作系统实验七 Shell编程之循环程序编程(上)
Linux操作系统实验七 Shell编程之循环程序编程
139 0
|
Java Windows
上机实验1 熟悉Java程序开发环境
上机实验1 熟悉Java程序开发环境
96 0
|
Linux 开发工具 C语言
Linux操作系统实验十二 Linux编程技术应用(下)
Linux操作系统实验十二 Linux编程技术应用
100 0
|
编译器 C语言
【程序环境和程序预处理】万字详文,忘记了,看这篇就对了(1)
1.程序翻译环境和运行环境 假设一个test.c文件经过编译器编译运行后生成可执行文件test.exe,这中间存在两个过程: 一个是翻译,在这个环境中源代码被转换为可执行的机器指令。 一个是运行,它用于实际执行代码。 在翻译环境阶段,会进行编译和链接操作。 在汇编阶段,是将汇编指令转换成二进制指令。 1.1程序翻译中的的编译和链接
【程序环境和程序预处理】万字详文,忘记了,看这篇就对了(2)
1.程序翻译环境和运行环境 假设一个test.c文件经过编译器编译运行后生成可执行文件test.exe,这中间存在两个过程: 一个是翻译,在这个环境中源代码被转换为可执行的机器指令。 一个是运行,它用于实际执行代码。 在翻译环境阶段,会进行编译和链接操作。 在汇编阶段,是将汇编指令转换成二进制指令。