使用命令行

命令行执行过程

当我们学习某一语法时,我们需要知道它是如何被执行的,当然对于特别底层的可以暂时不必深究,但是对于其大致过程需要了解。


\((1)\):命令shell使用实参替换用户输入的形参。

\((2)\):由多条命令构成的命令链或分组的单一命令行会被分解为单独的命令,每条命令带有自己的命令名与参数,并按序处理。

\((3)\):如果命令名带有文件路径,则命令shell使用该路径找到该命令,如果找不到则返回错误信息。

\((4)\):如果命令名没有指定文件路径,则命令shell会尝试对该命令名进行内部解析,若成功则说明是内置命令,随后立即执行;如果内部解析失败,则命令shell会在当前目录下查找该命令的可执行文件,之后搜索该可执行文件的命令路径,若所有这些位置都无法找到该命令,则返回错误信息。

\((5)\):如果命令成功定位,则命令使用指定的参数运行,包括那些要求输入的参数。其结果命令输出与错误信息会回显到命令窗口,或者写入到存储输出信息与错误日志的位置。


从上述执行过程,我们能够总结影响命令执行过程的因素包括以下方面:命令路径、重定向、命令链或分组。


启动命令行时传递参数

在上一篇中谈及到启动命令行主要有两种方式,一是搜索,二是Win+R。命令行在被启动时也可以传递参数,并执行相应的命令。这是常见的参数

我们以命令行参数/c为例,在运行框中输入

cmd /c "ipconfig> c:\data\ipconfig.txt"

那么会立刻打开cmd,稍后执行后面的内容,即将ipconfig的内容复制到文件ipconfig.txt中。需要注意的是,你必须有文件目录data,但是不需要文件ipconfig.txt。另外,某些特定的管理任务需要管理员权限,因此在参数无误的情况下请确保给予了管理员权限。


另外,若传递的参数在逻辑上是相悖的,则会执行最后一个参数,比如

cmd /a /u
cmd /e:on /e:off

第一个命令执行/u,第二个命令执行/e:off。这很好理解,虽然它们在逻辑上是相悖的,但是在时间上是可以连续执行,先执行第一个再执行第二个。


cmd的默认命令输出是ANSI字符而非Unicode字符,这意味着,如果你要更多的字符,需要手动使用上述参数。但是如果你当前打开的shell窗口是ANSI字符,而现在需要Unicode字符却又不想关闭当前的shell窗口,一个方法是使用嵌套技术。这项技术可以让一个命令行启动另一个命令行,新启动的命令行继承旧的命令行,同时新启动的命令行可以修改环境设置与参数又不影响旧的命令行,当新的命令行不需要时键入exit关闭,之后会退回到旧的命令行。如这里需要两次exit才可退出窗口,我只使用了一次


特殊字符是学习任何语法都会遇到的,它们的显著特征是承担了某些特殊的功能。如果我们不希望这些字符是特殊字符而是像普通字符那样,那么我们需要换码符引导,在Windows的cmd中,换码符是^。就类似于c/c++的转义序列那样。


命令路径

Windows操作系统是使用命令路径来定位可执行文件,其中又是根据文件扩展名来判断文件是否是可执行文件。通过path可以查看可执行文件的当前命令路径,笔者安装了vscode,所以命令路径略有不同。


对上述内容做一些解释。在Windows系统是使用“;”来隔断不同的命令路径以表示一个路径终点与另一个路径的起点。目录列出的先后顺序即为搜索可执行文件的先后顺序,所以

C:\Windows\system32

C:\Windows;

C:\Windows\System32\Wbem

以此类推


如果你想永久性改变当前系统环境的命令路径,可以使用setx,比如

setx PATH "C:\Scripts"

显示结果如下

这有一个缺点,它不能在当前shell窗口即时更新,若要查看更新后的命令路径,有两种方法。一是退出当前shell窗口重新打开;二是在控制面板中找到环境变量选项查看。


在修改命令路径时会改变原来的命令路径,除了上图环境变量面板中可以删除命令路径,也可以在命令行中做一些改变。

首先将path路径复写到一个文本中,比如.txt格式

打开这个文本修改其中的路径,将修改的内容复制下来

再使用setx设置path路径

内容复制下来以后,输入

setx PATH "C:\Users\31041\AppData\Local\Microsoft\WindowsApps;C:\Users\31041\AppData\Local\Programs\Microsoft VS Code\bin
"

再刷新cmd后即可恢复原来的命令路径。之所以会这么麻烦,那是因为setx只能增加命令路径不能删除命令路径。


除了永久性地修改path路径,也可在当前shell窗口临时修改path路径。比如

path %PATH%;C:\Scripts

使用该语句后只会在当前shell窗口生效,重启cmd后查看path,其值还是原来的。

一般更建议临时改变命令路径而非使用setx永久改变命令路径。


文件扩展与文件关联

文件扩展是操作系统标识文件格式的一种机制,比如.exe,.vbs等等。可执行文件的文件扩展也就是标识哪些文件扩展是可以直接运行的,它们是通过环境变量%PATHEXT%来设置的,可以通过set来查看。

在笔者的计算机中,可执行文件的文件扩展如图所示。PATHEXT值的顺序也即搜索可执行文件的顺序,在同一级目录下。比如在某个路径中,如果先搜索到.com的文件符合要求,则执行.com的文件,尽管后续的文件扩展可能也符合要求。


文件关联是指应用程序的文件扩展,通过文件关联可以将参数传递给可执行文件。文件关联规定了某个文件扩展由哪些应用程序打开,比如.pdf文件可以由你的系统上某一个应用程序打开。为了方便对系统中的每种文件扩展做更多的统计,对于文件扩展都有对应的文件类型。查看文件类型,可以使用assoc,如

assoc.exe

这样就可以查看.exe的文件类型,在笔者的计算机上如图

在多数情况下,文件类型在形式上是文件扩展的文本后跟随关键字file。比如cmdfile,exefile等等。


文件关联规定第一个传递的参数是命令名,其余参数传递给应用程序。查看某一个文件类型的文件关联可以使用ftype,如

ftype exefile

在笔者的计算机上如图所示

其输出结果

exefile="%1" %*

这样,在运行.exe时,第一个参数为要运行的命令,其余的则为要传递的参数。因为第一个参数赋给了文件类型,再根据映射追溯到哪个文件扩展,这正是要执行的命令。


用一则流程图简单表述如下。

graph LR A[文件扩展]-->|assoc|B[文件类型]-->|ftype|C[文件关联]==>D[规定了文件打开与执行]

有了assoc与ftype两个强大的武器,你就可以自定义一些文件如何被管理了。比如

assoc .ml=Myfile

然后再关联或者说创建映射

Myfile=C:\data\XXX.exe"%1" %*

这样你就得到了自定义的文件扩展,并且可以由你的应用程序打开。


重定向

在默认情况下,cmd的输入与输出是标准输入与标准输出。何谓标准输入与标准输出?即从命令指定的参数获取的输入信息为标准输入,将输出信息发送到cmd窗口的信息为标准输出。标准输入与标准输出有时会有一些局限性,因为有些信息不是从命令的参数中也不是输出到cmd窗口,而是与其它文件交互,这就需要重定向的技术。以下是常见的重定向语法。


命令的重定向

多数命令的输出是标准输出,多数情况下我们都可以将一个命令的标准输出作为其它的命令的输入,这其中用到的技术被称为管道。它的通常语法如下

command1 | command2

这不仅仅发生在两个命令上,也可以发生在多个命令上,只要这些命令都允许这种重定向即可。

command_1 | command_2 | ... | command_n

这里的符号|即为管道。


find与more

两个最常用于管道技术的命令是find与more。find命令可以在文件或传递给命令的输入文本中搜索特定的字符串,如果找到匹配的字符串,就列出匹配行的文本作为输出。比如dir可以获取某个文件的内容,可以将其作为输入,笔者以自己的计算机的D盘为例

dir D:\ find /I "game"

得到的内容如下


find根据你的需求可以设定不同的截取信息的方式,可以键入find /?获取语法帮助


more与find类似,但在逻辑上相反。more命令从其它命令接受输出信息作为自己的输入,并对输入信息进行截断,最后将截断结果显示在cmd窗口上。如果不做任何截取,则将全部接受的信息输出。例如


文件的重定向

前面交代的是与命令有关的重定向技术,这一部分介绍文件相关的重定向技术。如果是从文件的信息作为输入信息,则可以使用<,比如

sort < D:\temporary_file\test.txt

结果如下


同样,你也可以将输出信息发送给文件,使用>,比如

netstat -a > D:\temporary_file\test.txt

结果如下

从结果不难发现,原本的文件test.txt被重写了。事实上,>不但会重写文件,还会在没有文件的情况下创造文件。如果你不想重写原来的文件,而仅仅是在原来文件末端添加新的数据,可以使用>>,现在复归文件test.txt,并输入

netstat -a >> D:\temporary_file\test.txt

得到


文件的重定向操作主要依赖于>>><,它们之间也可以组合使用,例如

sort < filename_1 > filename_2

这样首先展示filename_1的内容,然后filename_1的内容会被写入到filename_2中。


标准错误输出的重定向

默认情况,命令执行的错误信息会作为输出信息发送到cmd窗口。有时我们希望错误输出到一个文件中。以下命令

chkdsk /r > D:\temporary_file\test.txt 2>&1

则将标准输出与标准错误都发送到文件中,以下是示例

从示例中可以看出,在命令行中不显示错误信息。如果你仅仅只是想将标准错误发送到文件,而将标准输出仍保留在cmd中,则可以

chkdsk /r 2> D:\temporary_file\test.txt

这是示例

所以标准输出与标准错误是不一样的,虽然很多时候它们相似。


命令链与命令分组

命令链与命令分组可以使命令按序、按条件地执行。以下是一些常见的语法


命令链

查询一个文件目录的内容可以使用命令链技术,你首先进入某一文件目录,之后获取文件目录的内容,这是两个步骤。通过如下命令

cd D:\Blog & dir /0:d

示例截图

通过&,可以按序执行命令,可是有时命令与命令间存在逻辑关系,比如第一个命令执行成功后再执行第二个命令

dir D:\temporary_file\test.txt && move D:\temporary_file\test.txt D:\VV

这里通过&&来进行条件执行,如果第一个命令失败了就不会执行第二个命令,以下是示例图

除了&&按条件执行命令,还有||也是按条件执行,区别在于,前者的条件是成功,而后者的条件是失败。比如

cd D:\temporary_file || cd D:\VV
xcopy D:\Blog\*.*

两个文件夹temporary_file与VV,如果前者打开失败则将Blog内容复制到VV中;反之复制到temporary_file中。这里不做演示。


命令分组

命令链既然是按序、按条件执行,那么很多命令间在执行就存在优先级。比如

hostname & ipconfig & netstat -a > D:\temporary_file\test.txt

最终结果

不难发现只有网络状态写入到文件中。若要将三个信息都写入到文件中,应使用( )来将前面三个命令作为一个整体,如下

( hostname & ipconfig & netstat -a ) > D:\temporary_file\test.txt

结果如下

cmd窗口中没有标准输出,也没有标准错误,也就是说它们全部被写入到文件中。除了( )进行命令分组外,还有if...else对命令进行分组。

posted @ 2025-04-23 21:33  永恒圣剑  阅读(58)  评论(0)    收藏  举报