我有一个单行代码段,它在命令行中工作得很好,但是当我将它作为批处理脚本的一部分运行时,它会失败并抛出错误。
以下命令的行为符合预期,删除文件夹中的所有空子文件夹。
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"
......它会抛出标准误差:
排序不被识别为内部或外部命令
在过去的一个小时左右的时间里,我一直在尝试是否转义管道,改变选项的顺序,查找dir
和sort
的文档,等等,但我仍然无法弄清楚这里发生了什么,批处理文件的其余部分,只有几行,工作正常,这是其中唯一失败的一行。
3条答案
按热度按时间t98cgbkg1#
A)Windows命令处理程序如何搜索命令?
Windows命令处理器搜索要执行的 * COMMAND *,
1.不是
cmd.exe
和的内部命令1.仅指定了文件名,而没有文件扩展名和路径
对于与模式
command.*
和匹配且具有本地环境变量PATHEXT
中列出的文件扩展名的文件1.当前目录中的第一个和
1.其次是本地环境变量
PATH
的所有目录。cmd.exe
的内部命令。它们是随Windows安装的控制台应用程序,位于目录%SystemRoot%\System32
中,文件名为sort.exe
、find.exe
、findstr.exe
、robocopy.exe
、xcopy.exe
...Windows上默认提供的此类控制台应用程序称为外部命令,以便更好地与未随Windows操作系统安装的控制台应用程序区分开来。
B)如何定义环境变量PATH?
PATH
变量有三种类型:1.* * System**
PATH
,用于所有帐户并存储在Windows注册表中的以下项下:1.* * 用户**
PATH
,仅用于当前帐户,存储在Windows注册表中的以下项下:1.* * 本地**
PATH
始终是启动当前进程的父进程的本地PATH
的副本。对于用作Windows桌面的Windows资源管理器示例,Windows将system和user
PATH
连接到localPATH
,桌面屏幕上的快捷方式以及Windows开始菜单和Windows任务栏作为用户的可视界面,称为Windows shell,用户通常从该界面启动程序。在启动新进程时,Windows为新进程复制正在运行进程的整个当前活动环境变量列表。Windows内核库函数CreateProcess根据函数参数
lpEnvironment
将此环境变量列表从当前进程的内存复制到新进程的内存(指向环境的长指针)为空指针。CreateProcess
函数之一总是在Windows上从另一个可执行文件启动一个可执行文件时使用。父进程不能修改任何子进程的环境变量,子进程也不能修改其父进程的环境变量。
这意味着一旦像
cmd.exe
这样的进程被启动来执行批处理文件,该进程就有了自己的环境变量集,只有进程本身可以修改,其他进程不能修改已经运行的进程的环境变量。C)错误消息是什么意思?
错误消息
'...'未被识别为内部或外部命令,
可操作程序或批处理文件。
总是意味着
已指定执行,很可能没有文件扩展名和可执行文件/脚本文件的(完整)路径和
PATH
的任何其他目录中找不到与模式FileName.*
匹配且文件扩展名列在当前活动环境变量PATHEXT
中的文件。D)出现此错误消息的可能原因是什么?
典型的原因是:
逐字符检查命令/可执行文件的名称。
在命令行上运行
echo Current directory is: %CD%
或将此行添加到命令行上方的批处理文件中,无法查看当前目录。验证要运行的可执行文件是否存在。一些安装包只有在之前安装了其他包(如Java、NPM、PHP等)的情况下才能工作。
PATH
中。在Windows控制面板中打开系统设置窗口,单击左侧的高级系统设置,单击按钮环境变量并在两个列表中查找
Path
及其值。默认情况下,Path
仅存在于系统变量列表中。PATH
后,未重新启动正在运行的进程/应用程序。用户或安装程序使用命令
setx
或通过控制面板-系统和安全-系统-高级系统设置-环境变量修改了系统PATH
或用户PATH
,但已运行的进程/应用程序(如打开的命令提示符或PowerShell窗口)未关闭/退出和打开/修改PATH
后重新启动。这是必要的,详见以下章节F)。%SystemRoot%\System32
中的可执行文件。**在处理器也支持x86指令集的64位Windows上,
%SystemRoot%\System32
目录包含64位可执行文件,%SystemRoot%\SysWOW64
目录包含32位可执行文件。大多数可执行文件都存在于这两个目录中。但也有一些可执行文件仅存在于System32
中,少数仅存在于SysWOW64
中。默认情况下,system
PATH
包含第一个文件夹路径%SystemRoot%\System32
。但是,在两个Windows系统文件夹中的哪一个中搜索指定的可执行文件(不带路径或带路径%SystemRoot%\System32
)取决于执行环境。在64位环境中执行的应用程序或脚本实际上访问的是%SystemRoot%\System32
,而在32位环境中执行的应用程序或脚本实际上访问的是%SystemRoot%\System32
。位环境被Windows file system redirector重定向到目录%SystemRoot%\SysWOW64
。在32位环境中运行的应用程序或脚本要在
%SystemRoot%\System32
中运行64位可执行文件,必须使用文件路径为%SystemRoot%\Sysnative
的可执行文件的完全限定文件名。%SystemRoot%\Sysnative
既不是目录,也不是任何类型的链接。它是一种非常特殊的东西,只存在于x86应用程序中。它不存在于amd64应用程序中。批处理文件中的条件if exist %SystemRoot%\Sysnative
在两种环境中始终为false,但if exist %SystemRoot%\Sysnative\cmd.exe
在32位执行环境中为true,在64位环境和32位Windows中为false。此条件可用于批处理脚本中,以确定批处理文件是否由64位Windows上%SystemRoot%\SysWOW64
中的32位cmd.exe
处理。根据任务,了解此条件可能很重要。另请参阅Microsoft文档WOW64 Implementation Details和Registry Keys Affected by WOW64。
PATH
包含对尚未定义的环境变量的引用。可以在
PATH
中使用对另一个环境变量(如SystemRoot
)的值的引用来指定文件夹路径。重要的是,此环境变量也在同一组环境变量或Windows首先处理的一组环境变量中定义。例如,如果将
%JAVA_HOME%\bin
添加到systemPATH
环境变量中,还必须定义一个system环境变量JAVA_HOME
,其中包含Java程序文件的基本文件夹路径。仅定义user环境变量JAVA_HOME
或稍后在local中定义环境变量JAVA_HOME
是不够的批处理文件的环境。如果将环境变量
JAVA_HOME
定义为system或user环境变量,但未在Windows命令进程的local环境中稍后定义的JAVA_HOME
上定义,则添加到user的%JAVA_HOME%\bin
将由Windows展开为完全限定的文件夹路径。在Windows开始菜单中对system或user
PATH
进行修改后打开一个新的command prompt窗口,运行set path
,输出PATH
不应再包含任何%Variable%
环境变量值引用。PATH
以前在命令行或批处理文件中修改过。在命令行上运行
set path
或将此命令添加到命令行上方的批处理文件中,无法查看环境变量PATH
和PATHEXT
的当前值。最后一个原因是在执行包含
set path=...
以上某处的批处理文件时未找到外部命令SORT。E)如何避免此错误消息?
最好是编写一个批处理文件,使其独立于
PATH
和PATHEXT
以及PATH
中的目录顺序,这意味着这里使用命令行:任何可执行文件存储在
%SystemRoot%\System32
中的外部命令都应在具有此路径和文件扩展名.exe
的批处理文件中指定。这样,Windows命令解释程序就不需要使用localPATH
和PATHEXT
搜索文件,并且批处理文件始终有效(只要环境变量SystemRoot
不在批处理文件中修改,我从未见过)。F)系统或用户PATH更改何时应用于进程?
当用户通过Windows开始菜单或从Windows资源管理器窗口打开命令提示符窗口时,用户使用选项
/K
隐式启动cmd.exe
,以在完成命令后保持控制台窗口打开,这有利于调试批处理文件。在Windows资源管理器中双击批处理文件时,用户启动
cmd.exe
处理批处理文件,并隐式使用选项/C
在批处理完成后关闭控制台窗口,这不利于调试批处理文件,因为在这种情况下看不到错误消息。在这两种情况下,Windows都会创建启动
cmd.exe
的应用程序(通常是Windows资源管理器)的环境变量副本。因此,启动的命令进程具有localPATH
,其值与启动cmd.exe
时的父进程相同。示例:
1.打开命令提示符窗口,运行
title Process1
和set path
。输出为
PATH
和PATHEXT
,与当前在窗口标题为 * Process 1 * 的控制台窗口中为当前用户帐户定义的一样。1.运行
set PATH=%SystemRoot%\System32
,然后再次运行set path
。输出仍然是
PATH
和PATHEXT
,但PATH
现在只包含一个目录。1.运行
start "Process2"
并在窗口标题为 * Process 2 * 的新控制台窗口中运行命令set path
。输出为
PATH
和PATHEXT
,其值与之前 * 过程1 * 中的值相同。这表明在启动新进程时,正在运行的进程的当前环境变量被复制,而不是Windows本身当前存储在Windows注册表中的变量。
1.在 * 进程2 * 中运行命令
set PATH=
和下一个命令set path
。输出仅为
PATHEXT
,因为localPATH
对于 * Process 2 * 不再存在。这说明每个进程都可以修改其环境变量,包括完全删除。
1.切换到 * Process 1 * 窗口,运行命令
set PATH=%PATH%;%SystemRoot%
,然后运行set path
。输出为
PATH
(包含两个目录)和PATHEXT
。1.运行命令
start "Process3"
,并在标题为 * Process 3 * 的打开窗口中运行命令set path
。输出为
PATH
,具有两个目录,这两个目录也是为 * Process 1 * 和PATHEXT
定义的。1.在 * 进程3 * 中运行命令
set PATH=%SystemRoot%\System32
。当
%SystemRoot%
扩展为C:\Windows
时,有3个命令进程正在运行,localPATH
的值如下:PATH=C:\Windows\System32;C:\Windows
PATH
根本不存在。PATH=C:\Windows\System32
那么,打开控制面板-系统-高级系统设置-环境变量并将值为
C:\Temp
的新环境变量PATH
添加到用户变量列表中,或者在已经存在用户PATH
环境变量的情况下,会发生什么情况?编辑PATH
并将;C:\Temp
附加到该值?只要打开显示两个列表的标题为环境变量的对话框窗口,修改变量时不会发生任何事情,直到单击按钮确定将所有更改接管到Windows注册表并关闭窗口。
我们回到三个正在运行的命令进程,分别在 * Process 1 、 Process 2 * 和 * Process 3 * 中运行命令
set path
,可以看到:PATH=C:\Windows\System32;C:\Windows
PATH
根本不存在。PATH=C:\Windows\System32
已在运行的进程上没有任何更改。
任何进程都不能修改不同运行进程的环境变量!
从Windows开始菜单打开另一个命令提示符窗口,并在第四个命令进程中运行命令
set path
。可以看到,第四个命令进程的localPATH
现在已附加目录C:\Temp
。然后关闭所有四个命令进程并删除添加的user
PATH
,如果之前附加了此目录路径,则从userPATH
中删除;C:\Temp
。如果没有进程可以修改已经运行的进程的环境变量,这怎么可能呢?
使用按钮确定关闭环境变量窗口时,如何修改作为Windows桌面运行的Windows资源管理器示例的环境变量列表?
eryksun在他的评论中给出了这两个问题的答案。
单击环境变量窗口的按钮确定,将对系统和用户变量的修改写入注册表后,Windows向所有顶层窗口发送WM_SETTINGCHANGE消息,以通知正在运行的应用程序系统参数已更改。
这取决于应用程序是否处理此事件消息以及如何处理。Windows桌面运行的Windows资源管理器从注册表中读取环境变量并相应地更新其环境变量列表。其他应用程序如Total Commander也处理此消息并更新其环境变量列表。但幸运的是
cmd.exe
没有这样做,因为这将是真正的问题。是否可以在命令提示符窗口或批处理文件中通过
WM_SETTINGCHANGE
通知修改system或user变量?可以使用
reg add
命令修改环境变量的注册表值。但这不会导致向所有顶级窗口发送WM_SETTINGCHANGE
消息。使用reg add
或regedit
进行的此类更改需要重新启动Windows(或至少注销并登录当前用户)才能考虑在内。但是还有一个命令
setx
,它是为修改system或user变量而设计的,并且在注册表根据指定的参数更新后,它也会向所有顶级窗口发送WM_SETTINGCHANGE
消息。在命令提示符窗口中运行setx /?
以了解详细信息。但是请注意,setx
不修改正在运行的命令进程的本地环境变量。这必须使用除setx
之外使用的命令set
来完成。G)Windows如何处理环境变量PATHEXT?
与环境变量
PATH
相比,Windows对带有文件扩展名列表的环境变量PATHEXT
的处理方式不同。系统
PATHEXT
和用户PATHEXT
未连接到本地PATHEXT
。用户
PATHEXT
替换*系统**PATHEXT
中在已定义用户PATHEXT
的帐户环境下运行的所有进程。默认情况下,仅定义了一个system
PATHEXT
环境变量。H)是否可以禁用当前目录中的文件搜索?
如果在命令行或批处理文件中指定了脚本文件或可执行文件的文件名,而没有任何路径,这意味着参数字符串中没有反斜杠
\
(或正斜杠/
,因为自动更正),则Windows命令处理器默认在当前目录中搜索。但是在Windows Vista和更高的Windows客户端版本上以及在Windows Server 2003和更高的Windows服务器版本上,确实有可能通过定义具有任何值的环境变量
NoDefaultCurrentDirectoryInExePath
来禁止在当前目录中搜索脚本/可执行文件,所述值由eryksun在其下面的注解中写入,并由Microsoft“s关于函数NeedCurrentDirectoryForExePathA的文档。有关此环境变量用法的更多详细信息,请参见Removing the current working directory from the path。
I)如何修改系统或用户路径?
用户最好使用Windows GUI对话框窗口环境变量修改system和user
PATH
环境变量。此对话框窗口可按如下方式打开:1.单击Windows开始菜单按钮。
1.在键盘上键入环境变量。
1.有提供的Windows的两个项目:
编辑系统环境变量
编辑帐户的环境变量
1.单击两个项目中的一个以打开"环境变量“窗口。
也可以打开Windows控制面板。接下来必须单击系统和安全性,并为显示选项 * 查看方式 * 选择 * 类别 *。接下来必须单击系统。必须单击左侧的高级系统设置,然后单击按钮环境变量...
如果键盘上有Pause键或至少有与Fn键的组合键,也可以通过按Windows徽标键+ Pause组合键打开系统窗口。另请参阅Microsoft文档页Keyboard shortcuts in Windows。
进一步的用户操作是自解释的,用于编辑上部列表中的user
Path
或下部列表中的systemPath
。xytpbqjk2#
很有可能是您在修改
PATH
变量,或者是在脚本的其他地方覆盖了它。由于sort
是一个外部命令,而不是命令行中的其他命令,如for
、dir
、rd
,这些命令都是cmd
内部命令。需要PATH
变量来查找命令。如果未定义PATH
,则仅在当前工作目录中搜索外部命令。还需要PATHEXT
变量来定义可执行文件的标准文件扩展名,如.com
,.exe
。因此,当sort
出现在命令提示符或批处理文件中时,系统将在当前工作目录和PATH
变量指定的所有目录中搜索基本名称为sort
且扩展名为PATHEXT
的文件。命令sort
实际上称为sort.exe
,通常位于C:\Windows\System32
中。djmepvbi3#
在我的例子中,我非常确定我没有弄乱
PATH
,我没有意识到path
和PATH
是相同的,CMD不区分大小写。