"X未被识别为内部或外部命令,可操作程序或批处理文件"的原因是什么?

Has*_*him 3 windows cmd batch-file

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

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

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

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

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

...它抛出了标准错误:

排序不被识别为内部或外部命令

我一直在尝试了一个小时左右,有和没有逃脱管,改变的选项的顺序,查找两者的文件dirsort等等,但我还是没能弄清楚这是怎么回事这里.批处理文件的其余部分(只有几行)工作正常,这是其中唯一失败的行.

有人可以帮忙吗?

Mof*_*ofi 16

A)Windows命令解释器如何搜索命令?

Windows命令解释程序搜索要执行的命令

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

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

  1. 首先在当前目录
  2. 接下来在本地环境变量的所有目录中PATH.

SORTFIND以及FINDSTRROBOCOPY以及XCOPY等许多命令都不是内部命令cmd.exe.他们与位于目录中安装了Windows控制台应用程序%SystemRoot%\System32具有文件名sort.exe,find.exe,findstr.exe,robocopy.exe,xcopy.exe,...

Windows上默认提供的此类控制台应用程序称为外部命令,可以更好地区分它们与未安装Windows操作系统的控制台应用程序.


B)如何定义环境变量PATH?

有三种类型的PATH变量:

  1. 系统 PATH用于所有帐户并存储在Windows注册表下的密钥:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
    
    Run Code Online (Sandbox Code Playgroud)
  2. 用户 PATH仅用于当前帐户并存储在Windows下的Windows注册表中:

    HKEY_CURRENT_USER\Environment
    
    Run Code Online (Sandbox Code Playgroud)
  3. 本地 PATH,它始终是启动当前进程的父进程的本地副本PATH.

Windows 将用作Windows桌面的Windows资源管理器实例的系统用户 连接PATH本地 PATH,桌面屏幕上的快捷方式和Windows开始菜单作为用户的可见界面.

在启动新进程时,Windows将为新进程复制正在运行的进程的整个当前活动环境变量表.

父进程不能修改任何子进程的环境变量,子进程也不能修改其父进程的环境变量.

这意味着一旦cmd.exe开始执行批处理文件的过程,该进程就有自己的一组环境变量,只有进程本身才能修改.没有其他进程可以修改已在运行的进程的环境变量.


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

错误消息

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

总是意味着

  1. 文件名

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


    指定执行很可能没有文件扩展名,没有(完整)路径到可执行文件/脚本文件

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


D)出现此错误消息的可能原因是什么?

典型的原因是:

1.由于输入错误,要执行的文件的文件名指定错误.

逐个字符检查命令/可执行文件的名称.

2.当前目录与包含要执行的文件的目录不同.

echo Current directory is: %CD%在命令行上运行或将此行添加到命令行上方的批处理文件中,该文件无法查看当前目录是什么.

3.根本没有安装要运行的可执行文件或脚本.

验证是否存在要运行的可执行文件.某些安装包仅在以前安装了Java,NPM,PHP等其他软件包时才有效.

4.要执行的文件的目录根本不存在 PATH .

在Windows 控制面板的" 系统设置"窗口中打开,单击左侧的" 高级系统设置 ",单击" 环境变量 "按钮,然后查看两个列表Path及其值.默认情况下Path,仅存在于系统变量列表中.

5.修改系统或用户后,未重新启动正在运行的进程/应用程序 PATH .

使用命令或通过控制面板进行系统 PATH用户的 修改- 系统 - 高级系统设置由用户或安装程序进行,但是已打开的进程/应用程序(如打开的命令提示符或PowerShell窗口)未关闭/退出并打开/ 修改后重新启动.这是必要的,如下面F)部分所述.PATHsetxPATH

6. 在命令行或批处理文件之前修改了LOCAL变量%SystemRoot%\System32 .

运行%SystemRoot%\System32命令行或添加此命令到无法看到的环境变量的当前值的命令行上面的批处理文件%SystemRoot%\SysWOW64System32.

最后一个原因是在执行包含上述某处的批处理文件时找不到外部命令SORTSysWOW64.


E)如何避免此错误消息?

Best编写了一个批处理文件,用于独立于PATH%SystemRoot%\System32目录的顺序,%SystemRoot%\System32这意味着在这里使用命令行:

FOR /f "delims=" %%d in ('dir /s /b /ad ^| %SystemRoot%\System32\sort.exe /r') do rd "%%d"
Run Code Online (Sandbox Code Playgroud)

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


F)何时将系统或用户PATH更改应用于进程?

当用户通过Windows开始菜单或在Windows资源管理器窗口中打开命令提示符窗口时,用户if exist %SystemRoot%\Sysnative以隐式使用选项启动,if exist %SystemRoot%\Sysnative\cmd.exe以在完成适合调试批处理文件的命令后保持控制台窗口打开.

在Windows资源管理器中双击cmd.exe批处理文件时,用户启动处理批处理文件,并使用隐式使用选项%SystemRoot%\SysWOW64在完成批处理后关闭控制台窗口,这对于调试批处理文件不利,因为在这种情况下无法看到错误消息.

在这两种情况下,Windows都会创建应用程序环境变量的副本,PATH通常是Windows资源管理器.因此,启动的命令进程具有本地, PATH其值与父进程在启动时的值相同SystemRoot.

例:

  1. 打开命令提示符窗口,运行%JAVA_HOME%\bin并运行PATH.
    输出是JAVA_HOMEJAVA_HOME如目前用于在具有现在窗口标题控制台窗口当前用户帐户中定义处理1.

  2. JAVA_HOME再次运行和下一次%JAVA_HOME%\bin.
    输出仍PATHJAVA_HOME,但JAVA_HOME现在只包含一个目录.

  3. PATH在新的控制台窗口中运行并运行,窗口标题为Process2命令set path.
    输出与Process1中的值相同PATH%Variable%具有相同的值. 这表明在启动新进程时,将复制正在运行的进程的当前环境变量,而不是Windows本身当前存储在Windows注册表中的那些变量.

  4. Process2中运行命令PATH,然后运行set path.
    输出仅仅PATH是因为Process2不再存在本地 . 这表明每个进程都可以修改其环境变量,包括完全删除.PATHEXT

  5. 切换到处理1窗口中运行命令set path=...和未来PATH.
    输出PATHEXT有两个目录和PATH.

  6. 运行命令%SystemRoot%\System32并在打开的窗口中使用标题Process3命令.exe.
    输出PATH有两个目录,也为Process1PATHEXT.

  7. Process3中运行命令SystemRoot.

当扩展为:时,有3个命令进程在运行时具有以下本地 值:cmd.exe/Kcmd.exe

Process1:/C
Process2:cmd.exe根本不存在.
过程3:PATH

那么现在在打开控制面板 - 系统 - 高级系统设置 - 环境变量以及向用户变量列表中添加带有值的环境变量cmd.exetitle Process1,或者如果已经有用户 set path环境变量,编辑 PATH并附PATHEXT加到值会发生什么?

好吧,只要打开带有显示两个列表的标题环境变量的对话框窗口,修改变量就没有任何反应,直到单击按钮确定以将所有更改接管到Windows注册表并关闭窗口.

让我们回到3个运行命令进程,并在Process1,Process2Process3中运行命令set PATH=%SystemRoot%\System32.可以被看见:

Process1:set path
Process2:PATH根本不存在.
过程3:PATHEXT

已经运行的进程没有任何改变.

没有进程可以修改正在运行的进程的环境变量.

从Windows开始菜单打开另一个命令提示符窗口并在第四个命令中运行命令处理PATH.可以看出,第四个命令进程的本地 现在start "Process2"已经附加了该目录set path.

然后关闭所有4个命令进程并删除添加的用户 ,如果之前已添加此目录路径,则PATH分别PATHEXT用户 删除set PATH=.

如果没有进程可以修改已经运行的进程的环境变量,那怎么可能呢?

如果在关闭环境变量窗口时使用按钮确定,Windows资源管理器实例的环境变量列表是如何运行的?

关于这两个问题的答案是由eryksun在他的评论中给出的.

在单击" 环境变量"窗口的" 确定 " 窗口中将系统用户变量的修改写入注册表后,Windows会将WM_SETTINGCHANGE消息发送到所有顶级窗口,以通知正在运行的应用程序有关已更改的系统参数的信息.

如果完全处理此事件消息以及如何处理,则由应用程序决定.运行为Windows桌面的Windows资源管理器从注册表中读取环境变量并相应地更新其环境变量列表.Total Commander等其他应用程序也处理此消息并更新其环境变量列表.但set path幸运的是,这不会那样做,因为这确实存在问题.

是否有可能通过命令提示符窗口或批处理文件中的通知来修改系统用户变量PATHEXT

可以使用PATH命令修改环境变量的注册表值.但这不会导致set PATH=%PATH%;%SystemRoot%向所有顶级窗口发送消息.使用set path或完成此类更改PATH需要重新启动Windows(或至少注销并登录当前用户)才能完全考虑.

但是还有一个命令PATHEXT用于修改系统用户变量,并且start "Process3"在根据指定的参数更新注册表之后还将消息发送到所有顶级窗口.set path在命令提示符窗口中运行以获取详细信 但请注意PATH不要修改运行命令进程的本地环境变量.必须PATHEXT使用除此之外使用的命令来完成此操作set PATH=%SystemRoot%\System32.


G)Windows如何处理环境变量PATHEXT?

与环境变量相比,PATH具有文件扩展名列表的环境变量由Windows处理%SystemRoot%.

系统 C:\Windows用户 PATH=C:\Windows\System32;C:\Windows不要串接到本地 PATH.

用户 PATH=C:\Windows\System32 替换系统 PATH下具有帐户的环境中运行的所有过程的用户 C:\Temp定义的.

默认情况下,仅定义了系统 PATH环境变量.


H)是否可以在当前目录中禁用文件搜索?

Windows命令处理器默认搜索当前目录中是否在命令行或批处理文件中指定了脚本文件或可执行文件的文件名而没有任何路径,这意味着参数字符串中没有反斜杠PATH(或者;C:\Temp由于自动更正而产生正斜杠) .

但是在Windows Vista和更高版本的Windows客户端版本以及Windows Server 2003和更高版本的Windows服务器版本上,set path通过PATH=C:\Windows\System32;C:\Windows使用任何写入的值定义环境变量,确实可以禁用在指定的当前目录中搜索脚本/可执行文件而不至少具有相对路径由eryksun在下面的评论中解释并由Microsoft在MSDN文章中解释函数NeedCurrentDirectoryForExePath.

有关此环境变量使用的更多详细信息,请参阅从路径中删除当前工作目录.

  • CMD的默认行为是首先在当前目录中搜索.我们可以通过定义环境变量"NoDefaultCurrentDirectoryInExePath"来跳过此步骤.然后为了安全起见,我们可以添加"." 最后明确地给`PATH`,或者至少在系统目录之后.如果我们不将它添加到`PATH`,那么在当前目录中运行文件必须使用显式相对路径,例如`.\ program.exe`. (4认同)
  • 如果由于某种原因你有一个没有扩展名(.exe或任何其他)的可执行文件,那么你可以通过附加";"来在CMD中运行它.到`PATHEXT`环境变量. (4认同)
  • 存储在注册表中的环境变量是"REG_SZ"或"REG_EXPAND_SZ"类型,它们引用其他`%variables%`.因为枚举注册表键没有设置顺序,所以Explorer会在4次传递中重新加载环境:系统`REG_SZ`,系统`REG_EXPAND_SZ`,用户`REG_SZ`和用户`REG_EXPAND_SZ`.`PATH`值几乎总是一个`REG_EXPAND_SZ`类型,它是根据动态值和`REG_SZ`值定义的.此外,用户的"PATH"被附加到系统值.重要的是要警告天真地使用setx.exe来修改`PATH`会使这个结构变平和扩展. (3认同)

asc*_*pfl 5

最有可能的是,你搞砸了这个PATH变量.也许你会在脚本中的其他地方覆盖它.由于sort是一个外部命令,不是所有的人在你的命令行一样for,dir,rd,这是cmd-internal命令时,PATH需要变量来查找命令.如果PATH未定义,则仅在当前工作目录中搜索外部命令.还有一种PATHEXT是需要定义标准的文件扩展名可执行文件,如变量.com,.exe.因此,当sort出现在命令提示符或批处理文件中时,系统将搜索当前工作目录和PATH变量指定的所有目录,以查找具有基本名称sort和指定的扩展名之一的文件PATHEXT.该命令sort实际上是被调用的sort.exe,通常位于C:\Windows\System32.