【问题标题】:Why are commands in batch script "not recognized" which are executed manually fine?为什么手动执行的批处理脚本中的命令“无法识别”?
【发布时间】:2016-12-13 07:46:29
【问题描述】:

我正在编写一个批处理脚本,从同一文件夹中的 MSI 文件安装一些应用程序。

当我在命令提示符窗口中编写这些命令时,一切都很好,所有命令都可以正常工作。

但是当我将它们写入批处理脚本时,突然大多数命令(例如XCOPYmsiexecDISM)都会导致如下错误消息:

'XCOPY' 不是内部或外部命令、可运行程序或批处理文件。

在谷歌上搜索了一段时间后,我看到很多与环境变量PATH 相关的 cmets,它应该包含C:\Windows\system32,我确保它包含在PATH 中。还找到了很多关于编写我已经尝试过但没有用的完整路径的答案。

我正在使用 Windows server 2012。

这是我的批处理文件的代码:

@echo off
set path=C:\                rem default path
rem get the path as parameter to the script:
set argC=0
for %%x in (%*) do Set /A argC+=1
if %argC% gtr 0  (set path=%1%)
IF %ERRORLEVEL% NEQ 0 (
    echo %me%: something went wrong with input directory
) 
echo Destenation: %path%

SETLOCAL ENABLEEXTENSIONS
SET me=%~n0
SET parent=%~dp0
echo %me%: starting installation of Python 2.7 64bit and Apache 64 bit
REM install .net 3.5
DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:installationMediaDrive:\sources\sxs
msiexec /i ".\py\python-2.7.amd64.msi" TARGETDIR=%path%/Python27 /passive /norestart ADDLOCAL=ALL
mkdir %path%\Apache24
XCOPY /e /Q ".\Apache24" %path%\Apache24

【问题讨论】:

  • 向我们展示您的代码
  • 嘿,谢谢你的回复,我添加了代码

标签: batch-file cmd windows-server-2012


【解决方案1】:

看起来批处理文件应该支持可选指定的安装目录路径作为第一个参数。用于检查此可选文件夹路径是否存在的代码非常混乱。肯定有更简单的方法来检查可选参数,如下所示。

主要问题是重新定义环境变量PATH,这导致Windows 的标准控制台应用程序存储在目录%SystemRoot\System32 中,并且命令解释器cmd.exe 在执行批处理文件时不再找到其他标准Windows 目录。

一般来说,如果这个完整的文件规范字符串包含空格字符或这些字符之一&()[]{}^=;!'+,`~,则需要使用双引号括起来的完整路径、文件名和文件扩展名来指定要执行的应用程序@如在关于在命令提示符窗口中运行的最后一个输出帮助页面上的最后一段 cmd /?

但主要是为了使人类用户更容易从命令提示符窗口中手动执行应用程序和脚本,如果指定没有路径且没有文件扩展名,Windows 命令解释器也可以找到要自行运行的应用程序或脚本。

因此,如果用户仅输入 xcopy 或批处理文件仅包含 xcopy,Windows 命令解释器将搜索匹配模式 xcopy.* 的文件,该文件扩展名在分号分隔的环境变量列表中定义PATHEXT 在当前目录中的第一个,如果在分号分隔的环境变量 PATH 列表中的所有目录中都没有找到合适的文件。

有3个环境变量PATH

  1. 系统 PATH 存储在以下 Windows 注册表中:

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

    system PATH 中的文件夹路径默认用于独立于所用帐户的所有进程。

  2. 用户 PATH 存储在以下 Windows 注册表中:

    HKEY_LOCAL_MACHINE\Environment
    

    user PATH 中的文件夹路径默认仅用于使用设置了 user PATH 的帐户运行的所有进程。

  3. local PATH 只是在当前正在运行的进程的活动环境中保存在内存中。

systemuser PATH 由 Windows 连接到单个 local PATH 用于进程。

每当一个进程启动一个新进程(如 Windows Explorer)启动 Windows 命令解释器以执行批处理文件时,Windows 都会为新进程创建当前运行进程的环境表的副本 .因此,无论进程在其自己的环境变量本地副本上发生什么变化,都不会影响所有其他已经运行的进程。对环境变量的局部更改只对自己的进程和由该进程修改其变量所启动的所有进程有效。

在启动批处理文件时,变量PATHPATHEXT 的值与在启动批处理文件时使用的相同用户帐户下打开的命令提示符窗口中运行时显示的值相同,命令set PATH 列出所有开始的变量PATH 名称不区分大小写。

现在让我们看一下批处理文件的第二行:

set path=C:\                rem default path

这一行重新定义了 local PATH 环境变量。因此环境变量PATH对执行批处理文件的命令进程有效,并且由该批处理文件启动的所有应用程序不再包含C:\Windows\System32;C:\Windows;...,而是现在只包含这个非常奇怪的单个文件夹路径。

C:\                rem default path

remcmd.exe 的内部命令,必须单独写一行。在 C++ 或 JavaScript 中的 // 等批处理代码中没有行注释。有关此命令的帮助,请在命令提示符窗口中运行 rem /?

在没有安装文件夹路径作为第一个参数的情况下运行批处理文件时,结果是 Windows 命令解释器仅在当前目录中搜索 dism.*msiexec.*xcopy.*,因为肯定没有名称为 @ 的目录987654365@ 在驱动器的根目录 C: 开头有很多空格/制表符。

结论:不宜使用path作为安装文件夹路径的变量名。

批处理代码中的另一个错误是使用%1% 指定批处理文件的第一个参数。这是错误的,因为批处理文件的参数使用%1%2、... 在命令提示符窗口中运行call /? 以获取有关引用批处理文件参数的帮助以及存在哪些可能性,例如%~dp0下面用于获取参数 0 的驱动器和路径,即批处理文件名,即包含当前正在运行的批处理文件的文件夹的路径。

我建议使用这个批处理代码:

@echo off
setlocal EnableExtensions
set "SourcePath=%~dp0"
set "BatchName=%~n0"
if "%~1" == "" (
    echo %BatchName% started without an installation folder path.
    set "InstallPath=C:\"
    goto StartInstalls
)

rem Get installation folder path from first argument
rem of batch file without surrounding double quotes.
set "InstallPath=%~1"

rem Replace all forward slashes by backslashes in case of installation
rem path was passed to the batch file with wrong directory separator.
set "InstallPath=%InstallPath:/=\%"

rem Append a backslash on installation path
rem if not already ending with a backslash.
if not "%InstallPath:~-1%" == "\" set "InstallPath=%InstallPath%\"

:StartInstalls
echo %BatchName%: Installation folder: %InstallPath%

echo/
echo %BatchName%: Installing .NET 3.5 ...
DISM.exe /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:installationMediaDrive:\sources\sxs

echo/
echo %BatchName%: Installing Python 2.7 64-bit ...
%SystemRoot%\System32\msiexec.exe /i "%SourcePath%py\python-2.7.amd64.msi" TARGETDIR="%InstallPath%Python27" /passive /norestart ADDLOCAL=ALL

echo/
echo %BatchName%: Installing Apache 2.4 64-bit ...
mkdir "%InstallPath%Apache24"
%SystemRoot%\System32\xcopy.exe "%SourcePath%\Apache24" "%InstallPath%Apache24\" /C /E /H /I /K /Q /R /Y >nul

endlocal

要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /? ... 用于解释%~dp0%~n0%~1
  • dism /?
  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • msiexec /?
  • rem /?
  • set /?
  • setlocal /?
  • xcopy /?

也请阅读

最后看看:

Windows 服务器的管理员应该将此处和引用页面上的所有内容都用小指扭转。

【讨论】:

  • 哇!非常感谢!我没有完全意识到它是如何工作的。它真的帮助并解决了我的问题。使某些命令可用的另一件事是直接从 sys32 文件夹中调用它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
  • 2019-06-25
相关资源
最近更新 更多