我有一个批处理文件,它与我想要使用xcopy
的文件在同一个目录中。但由于某些原因,找不到该文件。
我认为当前目录始终是批处理文件所在的位置。
我以管理员身份运行批处理文件。这发生在一台Windows 7 64位桌面计算机上。
批处理文件:
@ECHO OFF
XCOPY /y "File1.txt" "File2.txt"
PAUSE
错误:
File not found - File1.txt
0 File(s) copied
我有一个批处理文件,它与我想要使用xcopy
的文件在同一个目录中。但由于某些原因,找不到该文件。
我认为当前目录始终是批处理文件所在的位置。
我以管理员身份运行批处理文件。这发生在一台Windows 7 64位桌面计算机上。
批处理文件:
@ECHO OFF
XCOPY /y "File1.txt" "File2.txt"
PAUSE
错误:
File not found - File1.txt
0 File(s) copied
使用上下文菜单项以管理员身份运行批处理文件时,当前工作目录取决于当前用户的用户账户控制(UAC)设置。
可以通过以下小批处理文件 C:\Temp\Test.bat
进行演示:
@echo Current directory is: %CD%
@pause
在用户账户控制设置中选择了以下选项:
默认 - 只在程序试图更改计算机时通知我
- 当我更改Windows设置时不要通知我
并使用以管理员身份运行,Windows会使用注册表键。
HKEY_CLASSES_ROOT\batfile\shell\runasuser\command
该注册表键不包含用于执行批处理文件的默认字符串。相反,它具有带有CLSID {ea72d00e-4960-42fa-ba92-7792a7944c1d}
的字符串值DelegateExecute
。
结果是打开一个标题为用户账户控制的对话框,文本如下:
您要允许以下程序对计算机进行更改吗?
程序名称:Windows命令处理器
已验证发布者:Microsoft Windows
经过用户确认后,Windows会暂时打开一个新的用户会话,就像在命令行上使用RunAs一样。
在这个新的用户会话中,当前工作目录是%SystemRoot%\System32
,现在执行由Windows注册表中键的默认字符串定义的命令。
HKEY_CLASSES_ROOT\batfile\shell\runas\command
即:
%SystemRoot%\System32\cmd.exe /C "%1" %*
因此,将打开一个标题为C:\Windows\System32\cmd.exe的控制台窗口,并显示2行:
Current directory is: C:\Windows\System32
Press any key to continue . . .
按下任意键后,批处理执行就会结束,导致关闭 cmd.exe
,从而关闭用户会话。
但如果在用户帐户控制设置中选择了以下选项:
不要在发生以下情况时通知我:
程序尝试安装软件或更改计算机设置
我更改了 Windows 设置
则行为会有所不同,因为用户已经拥有提升的特权。
现在 Windows 直接使用以下命令:
%SystemRoot%\System32\cmd.exe /C "%1" %*
根据默认键的字符串
HKEY_CLASSES_ROOT\batfile\shell\runas\command
当前用户会话中。
结果是打开一个控制台窗口,窗口标题为C:\Windows\System32\cmd.exe,但显示的内容是:
Current directory is: C:\Temp
Press any key to continue . . .
由于在这种情况下不需要切换到不同的用户会话,因此父进程(桌面的Windows资源管理器)的当前工作目录用于执行批处理文件。
PA 在他的回答中已经发布了2个可能的解决方案,我在此复制他的回答并进行了小改进(使用带引号的目录路径的pushd),并增加了第三个解决方案。
使用 pushd 和 popd 将当前目录更改为批处理文件所在的目录:
pushd "%~dp0"
%SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
popd
这也适用于UNC路径。在命令提示符窗口中运行pushd /?
以了解为什么这也适用于UNC路径。
在源和目标规范中使用批处理文件的目录:
%SystemRoot%\System32\xcopy.exe "%~dp0File1.txt" "%~dp0File2.txt" /Y
使用cd命令将工作目录更改为批处理文件所在的目录:
cd /D "%~dp0"
%SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
因为命令解释器cmd默认情况下不支持将UNC路径作为当前目录,所以此方法无法用于UNC路径。有关详细信息,请参见CMD does not support UNC paths as current directories。
为了完整性和隐蔽性,我另外提供一种解决方法,并已在Windows 8.1下确认可行,预计在其他系统中也可以用,因为它依赖于文档记录的功能:
您可以更改runas
命令定义键
HKEY_CLASSES_ROOT\batfile\shell\runas\command
和
HKEY_CLASSES_ROOT\cmdfile\shell\runas\command
为以下内容
%SystemRoot%\System32\cmd.exe /S /C "(for %%G in (%1) do cd /D "%%~dpG") & "%1"" %*
runas
动词启动时,bat
或cmd
文件分别从它们所在的目录开始。 "以管理员身份运行"菜单项。
原始命令的添加内容的确切作用:
cmd /S
剥离了/C
后面命令字符串的第一个和最后一个(双引号)for %%G in (%1) do
枚举其单个条目,%1
参数可以作为循环体中的%%G
进行扩展;字母是任意的,但有些字母可能是“保留的”。%%~dpG
扩展到%%G
的drive和path;如果存在引号,则~波浪号将其去除,这就是为什么我们需要明确地添加引号的原因。cd /D
将驱动器和目录都更改为其参数,最后&
运行第二个命令"%1" %*
,而不管第一个命令的成功与否。您可以使用pushd
,甚至支持UNC路径,但一个杂散的popd
会使任何脚本停留在system32
目录中,这不是我喜欢的行为。
这也可以对exefile
条目进行操作,但说实话,与其尝试更改我的系统,我宁愿接受不一致性。
享受打败操作系统安全机制的过程 :)
file1.txt
。echo BAT directory is %~dp0
echo Current directory is %CD%
either change the current directory to match the expected one
pushd %~dp0
XCOPY /y "File1.txt" "File2.txt"
popd
or specify the full path in the command
XCOPY /y "%~dp0File1.txt" "%~dp0File2.txt"
CD
,因为它可以正常工作。所以这不是一致的。 - mcu
xcopy
就可以工作,但仅使用文件名就不行。 - mcuDIR
添加到批处理文件中,在屏幕上转储了一堆文件 - 看起来像是system32
目录。 - mcuxcopy /y "%~dp0File1.txt" "%~dp0 File2.txt"
。 - wOxxOm