windows - “无法将X识别为内部或外部命令,可操作程序或批处理文件”的原因是什么?

标签 windows batch-file cmd

我有一个单行代码段,可在命令行中完美运行,但是当我将其作为批处理脚本的一部分运行时会失败并引发错误。

以下命令将按预期方式运行,删除文件夹中的所有空子文件夹。

for /f "delims=" %d in ('dir /s /b /ad ^| sort /r') do rd "%d"


但是,当放入这样的批处理文件时...

FOR /f "delims=" %%d in ('dir /s /b /ad ^| sort /r') do rd "%%d"


...会引发标准错误:


无法将排序识别为内部或外部命令


在过去的一个小时左右的时间里,我一直在尝试并没有逃脱管道,更改选项的顺序,查找dirsort的文档等问题,但是我仍然无法弄清楚这里发生了什么。批处理文件的其余部分(只有几行)可以正常工作,这是其中唯一失败的行。

有人可以帮忙吗?

最佳答案

A)Windows命令处理器如何搜索命令?
Windows命令处理器搜索COMMAND以执行

不是cmd.exe的内部命令,并且
只是使用没有扩展名和路径的文件名指定

用于匹配模式command.*并在本地环境变量PATHEXT中列出文件扩展名的文件

首先在当前目录中
本地环境变量PATH所有目录中的下一个。

SORT和FIND和FINDSTR和ROBOCOPY和XCOPY以及更多命令不是cmd.exe的内部命令。它们是随Windows安装的控制台应用程序,位于目录%SystemRoot%\System32中,文件名为sort.exefind.exefindstr.exerobocopy.exexcopy.exe,...。
Windows上默认可用的此类控制台应用程序称为外部命令,以更好地将它们与未随Windows操作系统安装的控制台应用程序区分开。

B)如何定义环境变量PATH?
PATH变量有3种类型:

系统PATH,用于所有帐户,并存储在Windows注册表中的项下:

 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment


用户PATH仅用于当前帐户,并存储在Windows注册表中的键下:
 HKEY_CURRENT_USER\Environment


本地PATH始终是启动当前进程的父进程的本地PATH的副本。


Windows将用作Windows桌面的Windows资源管理器实例的系统和用户PATH连接到本地PATH,并使用桌面屏幕上的快捷方式和Windows开始菜单作为用户的可见界面。
在启动新进程时,Windows会为新进程复制正在运行的进程的整个当前活动环境变量表。
父进程无法修改任何子进程的环境变量,子进程也不能修改其父进程的环境变量。
这意味着一旦启动像cmd.exe这样的进程来执行批处理文件,该进程就会拥有自己的一组环境变量,只有该进程本身才能修改。没有其他进程可以修改已经运行的进程的环境变量。

C)错误消息是什么意思?
错误讯息

'...'未被识别为内部或外部命令,可操作程序或批处理文件。

总是意味着

一个的文件名

控制台应用程序
GUI应用
脚本(批处理文件,PowerShell脚本,Perl脚本,VBScript,JScript等)

被指定为最有可能在没有文件扩展名和没有(完整)可执行文件/脚本文件路径的情况下执行,并且

Windows无法在当前目录的当前活动环境变量FileName.*或当前活动环境变量PATHEXT的任何其他目录中找到与模式PATH匹配且文件扩展名匹配的文件。



D)此错误消息的可能原因是什么?
典型原因有:
1.由于键入错误,指定要执行的文件的文件名错误。
逐字符检查命令/可执行文件的名称。
2.当前目录不同于包含要执行的文件的目录。
在命令行上运行echo Current directory is: %CD%或将此行添加到命令行上方的批处理文件中,该命令行无法查看当前目录是什么。
3.根本没有安装要运行的可执行文件或脚本。
验证是否存在要运行的可执行文件。仅当以前安装了Java,NPM,PHP等其他软件包时,某些安装软件包才起作用。
4.要执行的文件目录根本不在PATH中。
在Windows控制面板中打开系统设置窗口,单击左侧的高级系统设置,单击环境变量按钮,然后在两个列表中查找Path及其值。默认情况下,Path仅存在于系统变量列表中。
5.修改系统或用户PATH后,没有重新启动正在运行的进程/应用程序。
用户或安装程序使用命令PATH或通过控制面板–系统–高级系统设置修改了系统PATH或用户setx,但已运行的进程/应用程序(如打开的命令提示符或PowerShell)修改PATH后,窗口未关闭/退出并打开/重新启动。如下面的F)章中所述,这是必要的。
6.在64位Windows上找不到%SystemRoot%\System32中的可执行文件。
在64位Windows上,目录%SystemRoot%\System32具有64位可执行文件,而%SystemRoot%\SysWOW64具有32位可执行文件。大多数可执行文件都存在于两个目录中。但是,有些可执行文件仅存在于System32中,而只有少数可执行文件仅存在于SysWOW64中。
默认情况下,系统PATH包含作为第一个文件夹路径%SystemRoot%\System32。但是,在两个Windows系统文件夹中的哪个文件夹中搜索没有路径或使用路径%SystemRoot%\System32指定的可执行文件取决于执行环境。在64位环境中执行的应用程序或脚本实际上是在访问%SystemRoot%\System32,而在Windows 32位环境中执行的应用程序或脚本由Windows file system redirector重定向到目录%SystemRoot%\SysWOW64
要在%SystemRoot%\System32中运行64位可执行文件的在32位环境中运行的应用程序或脚本,必须使用文件路径为%SystemRoot%\Sysnative的可执行文件的完全限定文件名。
注意:%SystemRoot%\Sysnative既不是目录,也不是任何类型的链接。这是仅适用于x86应用程序的非常特殊的东西。对于amd64应用程序不存在。在两个环境中,批处理文件中的条件if exist %SystemRoot%\Sysnative始终为false,但在32位执行环境中if exist %SystemRoot%\Sysnative\cmd.exe为true,在64位环境中以及32位Windows上为false。此条件可用于批处理脚本中,以了解批处理文件是否由64位Windows上的cmd.exe中的32位%SystemRoot%\SysWOW64处理。根据任务的不同,了解这一点很重要。
另请参阅Microsoft文档WOW64 Implementation DetailsRegistry Keys Affected by WOW64
7. PATH包含对一个(尚未)定义的环境变量的引用。
可以在PATH中使用对另一个环境变量(例如SystemRoot)的值的引用来指定文件夹路径。重要的是,还要在同一组环境变量或Windows首先处理的一组环境变量中定义此环境变量。
例如,如果将%JAVA_HOME%\bin添加到系统PATH环境变量,则还必须使用Java程序文件的基本文件夹路径定义一个系统环境变量JAVA_HOME。仅在批处理文件的本地环境中定义用户环境变量JAVA_HOME或稍后定义环境变量JAVA_HOME是不够的。
如果将环境变量%JAVA_HOME%\bin定义为系统或用户环境变量,但后来不在PATH的本地环境中定义的JAVA_HOME上,则Windows将添加到用户JAVA_HOMEPATH扩展为标准文件夹路径。 Windows命令进程。
通过从Windows开始菜单对系统或用户set path进行修改并运行PATH之后,打开新的command prompt窗口,可以很容易地看到这种错误。输出%Variable%不应再包含任何PATH环境变量值引用。
8.在命令行或批处理文件之前,已修改LOCAL变量set path
在命令行上运行PATH或将此命令添加到命令行上方的批处理文件中,该命令行无法查看环境变量PATHEXTset path=...的当前值。
最后一个原因是在执行包含在PATH上方某处的批处理文件时找不到外部命令SORT的原因。

E)如何避免此错误消息?
最好是编写一个独立于PATHEXTPATH以及%SystemRoot%\System32中的目录顺序的批处理文件,这意味着在此处使用命令行:
FOR /f "delims=" %%d in ('dir /s /b /ad ^| %SystemRoot%\System32\sort.exe /r') do rd "%%d"

可执行文件存储在.exe中的任何外部命令都应在具有此路径和文件扩展名PATH的批处理文件中指定。然后,Windows命令解释器不需要使用本地PATHEXTSystemRoot搜索文件,并且批处理文件始终有效(只要我从未见过的批处理文件中还没有修改环境变量cmd.exe即可) 。

F)何时将系统或用户PATH更改应用于进程?
当用户通过Windows开始菜单或从Windows资源管理器窗口中打开命令提示符窗口时,用户使用/K选项以隐式方式启动cmd.exe,以使控制台窗口在完成调试批处理命令后保持打开状态文件。
在Windows资源管理器中双击批处理文件时,用户在完成批处理后,使用选项/C启动cmd.exe以隐式方式使用该批处理文件处理批处理文件,这不利于调试批处理文件作为错误消息在这种情况下看不到。
在这两种情况下,Windows都会从PATH开始创建应用程序的环境变量副本,通常是Windows资源管理器。因此,启动的命令进程具有本地cmd.exe,其值与父进程启动title Process1时的值相同。
例:

打开命令提示符窗口,运行set path并运行PATH
输出是当前在控制台窗口中为当前用户帐户定义的PATHEXTset PATH=%SystemRoot%\System32,该窗口现在具有窗口标题Process1。

运行set path,然后再次运行PATH
输出仍然是PATHEXTPATH,但是现在start "Process2"仅包含一个目录。

运行set path并在窗口名称为Process2的新控制台窗口中运行命令PATH
输出为PATHEXTset PATH=,其值与Process1中的值相同。
这表明在启动新进程时,将复制正在运行的进程的当前环境变量,而不是Windows本身当前存储在Windows注册表中的变量。

在Process2中运行命令set path和下一个PATHEXT
输出仅为PATH,因为对于Process2,本地set PATH=%PATH%;%SystemRoot%不再存在。
这表明每个进程都可以修改其环境变量,包括完全删除。

切换到Process1窗口,运行命令set path和下一个PATH
输出为带有两个目录的PATHEXTstart "Process3"

运行命令set path,在打开的窗口中,标题为Process3的命令为PATH
输出为PATHEXT,其中有两个目录也为Process1和set PATH=%SystemRoot%\System32定义。

在Process3中运行命令PATH


%SystemRoot%扩展到C:\Windows时,将为本地PATH=C:\Windows\System32;C:\Windows运行以下3个命令进程:
流程1:PATH
Process2:PATH=C:\Windows\System32根本不存在。
流程3:PATH
所以现在打开控制面板-系统-高级系统设置-环境变量并将新的环境变量C:\Temp的值添加为PATH或在已有用户PATH环境的情况下会发生什么变量,编辑;C:\Temp并将set path附加到值?
好吧,只要打开显示两个列表的标题为“环境变量”的对话框窗口,修改变量就不会发生任何事情,直到单击“确定”按钮将所有更改都接管到Windows注册表中并关闭该窗口。
让我们返回到三个正在运行的命令进程,并在Process1,Process2和Process3中运行命令PATH=C:\Windows\System32;C:\Windows。可以被看见:
流程1:PATH
Process2:PATH=C:\Windows\System32根本不存在。
流程3:set path
已经运行的进程没有任何变化。
任何进程都不能修改其他正在运行的进程的环境变量!
从Windows的开始菜单中打开另一个命令提示符窗口,并在第四个命令进程中运行命令PATH。可以看出,第四个命令进程的本地C:\Temp现在已经添加了目录PATH
然后关闭所有四个命令进程,并删除添加的用户;C:\Temp,如果之前已附加此目录路径,则分别从用户PATH中删除​​cmd.exe
如果没有进程可以修改已经运行的进程的环境变量,怎么办?
在关闭“环境变量”窗口并单击“确定”时,如何修改在Windows桌面上运行的Windows资源管理器实例的环境变量列表?
eryksun在他的评论中给出了关于这两个问题的答案。
单击环境变量窗口中的确定按钮,将对系统和用户变量的修改写入注册表后,Windows将WM_SETTINGCHANGE消息发送到所有顶级窗口,以通知正在运行的应用程序有关已更改的系统参数的信息。
是否完全处理此事件消息以及如何处理,取决于应用程序。作为Windows桌面运行的Windows资源管理器从注册表读取环境变量并相应地更新其环境变量列表。其他应用程序(如Total Commander)也处理此消息,并更新其环境变量列表。但是WM_SETTINGCHANGE并没有这样做,因为这确实很成问题。
是否有可能在命令提示符窗口或批处理文件中通过reg add通过通知修改系统或用户变量?
使用WM_SETTINGCHANGE命令可以修改环境变量的注册表值。但这不会导致将reg add消息发送到所有顶级窗口。使用regeditsetx进行的此类更改完全需要考虑重新启动Windows(或至少注销并登录当前用户)。
但是,还有一个WM_SETTINGCHANGE命令,用于修改系统或用户变量,并且在根据指定的参数更新注册表后,还会将setx /?消息发送到所有顶级窗口。有关详细信息,请在命令提示符窗口中运行setx。但请注意set不会修改正在运行的命令进程的本地环境变量。这必须通过使用setx以外的命令PATHEXT完成。

G)Windows如何处理环境变量PATHEXT?
Windows处理与文件扩展名列表有关的环境变量PATH与环境变量PATHEXT相比有所不同。
系统PATHEXT和用户PATHEXT未连接到本地PATHEXT
用户PATHEXT将系统PATHEXT替换为在已定义用户PATHEXT的帐户环境下运行的所有进程。
默认情况下,仅定义系统\环境变量。

H)是否可以禁用当前目录中的文件搜索?
默认情况下,Windows命令处理器在当前目录中搜索脚本文件或可执行文件的文件名是否在命令行或批处理文件中指定,而没有任何路径,这意味着没有反斜杠/(或由于自动而没有正斜杠.\) -更正)。
但是,在Windows Vista和更高版本的Windows客户端版本以及Windows Server 2003和更高版本的Windows服务器版本上,确实可以通过定义环境变量NoDefaultCurrentDirectoryInExePath >具有eryksun在下面的注释中所写的任何值,并且由Microsoft关于函数NeedCurrentDirectoryForExePathA的文档进行了解释。
有关使用此环境变量的更多详细信息,请参见Removing the current working directory from the path

关于windows - “无法将X识别为内部或外部命令,可操作程序或批处理文件”的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41454769/

相关文章:

batch-file - 在 vscode 中为 .bat 文件中的 'start' 命令打开一个新终端

batch-file - 为什么 setlocal 会干扰 Windows 批处理文件中的 chdir?

python - 使用 PIP 时出现 "SSL: CERTIFICATE_VERIFY_FAILED"错误

powershell - 批处理脚本在文件夹中查找空文件

windows - 如何在长 PowerShell 命令中使用变量而不破坏命令

windows - R 脚本的 GUI 前端

windows - 如何使用批处理文件将多个命令插入到批处理文件中

windows - 命令行有效 - .Bat 脚本无效

windows - 从 windows .bat 文件启动 docker 工具箱

android - Nativescript Sidekick错误: Cannot find suitable v8 version! Android云构建