将带有空格的路径作为参数传递给 bat 文件

我有一个简单的 bat 脚本,它将文件从一个已知目录复制到用户指定的目录。如何将路径(它可能包含空格)传递给脚本并与 xcopy 命令一起使用它?


在我的代码中,我有以下内容

:READ_PWA_PATH
if "%1" == "" (
rem Set default path
set PWA_PATH="C:\Program Files\PWA"
rem
echo You have not specified your PWA url.
echo Default will be assumed: C:\Program Files\PWA.
choice /C:YN /M:"Do you wish to continue [Y] or cancel the script [N]?"
IF ERRORLEVEL ==2 GOTO CANCEL
IF ERRORLEVEL ==1 GOTO READ_WSS_SERVER_EXTENSIONS_PATH
GOTO END
) else (
set PWA_PATH=%1
)

如果我简单地调用脚本,我会得到以下错误:

C:\Projects\Setup>install.cmd "C:\program files (x86)"


-----------------
SETUP SCRIPT
-----------------


files was unexpected at this time.
C:\Projects\Setup>
213589 次浏览

如果路径中有空格,则必须用引号(“)围绕它。

不知道你是不是想问这个?

有趣的一个。我喜欢收集关于 cmd/command 中引号处理的引号。

您的特定脚本通过使用% 1而不是“% 1”来修复! ! !

通过添加一个“ echo on”(或者去掉一个 echo off) ,您可以很容易地发现这一点。

@echo off
setlocal enableextensions enabledelayedexpansion


if %1=="" (
rem Set default path
set PWA_PATH="C:\Program Files\PWA"
rem
echo You have not specified your PWA url.
echo Default will be assumed: C:\Program Files\PWA.
choice /C:YN /M:"Do you wish to continue [Y] or cancel the script [N]?"
IF ERRORLEVEL ==2 GOTO CANCEL
IF ERRORLEVEL ==1 GOTO READ_WSS_SERVER_EXTENSIONS_PATH
GOTO END
) else (
set PWA_PATH=%1
@echo !PWA_PATH! vs. %1
goto end
)
:READ_WSS_SERVER_EXTENSIONS_PATH
echo ok
goto end
:CANCEL
echo cancelled
:end
echo. final %PWA_PATH% vs. %1

正如 VardhanDotNet提到的,%1就足够了。

"%1%"会在引号周围加上引号: ""c:\Program Files\xxx""的意思是:

  • ’em pty string’("") ,
  • 后面跟着“ c: Program”,
  • 接下来是“意想不到的这里”“文件 xxx”,
  • 后跟一个空字符串("")

但是请注意,如果需要在 IF子句中使用 PWA_PATH,则需要将 if 引用为 !PWA_PATH!(因此 enabledelayedexpansion作为脚本的开头)

我认为 OP 的问题在于他想做以下的 都有:

  • 传递一个可能包含空格的参数
  • 测试参数是否丢失

正如一些海报所提到的,要传递包含空格的参数,必须在实际参数值周围加上双引号。

为了测试一个参数是否丢失,我一直学习的方法是:

if "%1" == ""

但是,如果引用了实际参数(如果值包含空格则必须如此) ,那么这将变成

if ""actual parameter value"" == ""

这会导致“意外”错误

if %1 == ""

那么引号值不再出现错误。但是在这种情况下,当值丢失时,测试 已经没用了变成

if  == ""

为了解决这个问题,在测试中使用任何其他字符(除了对 DOS 有特殊意义的字符)而不是引号:

if [%1] == []
if .%1. == ..
if abc%1xyz == abcxyz

使用 "%~1"。单独的 %~1删除周围的引号。但是,由于您无法知道输入参数 %1是否带有引号,因此应该通过 "%~1"确保添加了引号。这在连接变量(例如 convert.exe "%~1.input" "%~1.output")时特别有用

如果您的路径包含空间,那么尝试使用 %~s1。这将删除空格并将 ~1附加到您的路径,更重要的是,它指的是您的文件的绝对路径。试试用它。

“% ~ 1”在大多数情况下是有效的,但是有一些事情你需要注意:

  1. Windows NT 4.0不支持。您需要 Windows2000或更高版本。(如果您正在编写与旧操作系统兼容的脚本,请注意。)
  2. 它不能保证参数的安全和消毒。我的观察是,在 CMD 脚本中有 无法正确地清除命令行参数

为了说明第二点,让我举一个例子:

REM example.cmd
ECHO %~1

运行 example.cmd dummy^&DIR。这里转义了与符号(^&) ,以防止 shell 将其解释为命令分隔符,从而使其成为传递给脚本的参数的一部分。DIR 被解释为一个命令 在运行脚本的子 shell 中,在这里它不应该。

引用这句话可能会在一段时间内奏效,但仍不安全:

REM example2.cmd
SETLOCAL EnableExtensions EnableDelayedExpansion
SET "arg1=%~1"
ECHO "%~1"
ECHO !arg1:"=!

example2.cmd foo^"^&DIR^&^"bar会打破它。DIR 命令将运行两次,一次在 SET 之后,另一次在第一个 ECHO 之后。你可以看到你认为被引用的 "%~1"被参数本身所引用。

因此,无法保证解析参数的安全性。

(编辑: EnableDelayedExpansion在 WindowsNT4中也不能工作。感谢这里的信息: http://www.robvanderwoude.com/local.php)

假设您希望通过在 C # 代码中执行批处理文件来备份数据库。下面是一个完全可行的解决方案,它处理路径中的空白。 这在 Windows 中是可行的,不过我还没有用 mono 测试过。

C # 代码:

        public bool BackupDatabase()
{
bool res = true;
string file = "db.bat";
if (!File.Exists(file)) return false;


BackupPaths.ForEach(path =>
{
Directory.CreateDirectory(path);


string filePath = Path.Combine(path, string.Format("{0}_{1}.bak", Util.ConvertDateTimeToFileName(false), DatabaseName));
Process process = new Process();
process.StartInfo.FileName = file;
process.StartInfo.Arguments = string.Format(" {0} {1} \\\"{2}\\\""
, DBServerName
, DatabaseName
, filePath);


process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;


try
{
process.Start();
process.WaitForExit();
}
catch (Exception ee)
{
Logger.Log(ee);
res = false;
}
});
return res;
}

这是批处理文件:

@echo OFF
set DB_ServerName=%1
set Name_of_Database=%2
set PathToBackupLocation=%3


echo Server Name = '%DB_ServerName%'
echo Name of Database = '%Name_of_Database%'
echo Path To Backup Location = '%PathToBackupLocation%'


osql -S %DB_ServerName% -E -Q "BACKUP DATABASE %Name_of_Database% TO DISK=%PathToBackupLocation%"

在特殊情况下,如果您希望始终默认为工作目录,或者仅当没有传入参数时才默认为工作目录,那么您可以使用 %CD%

根据 服务器故障答案:

Windows 在 psuedo 环境变量 %CD%中维护工作目录。

请查看这篇文章中的一个很好的例子,以及如何通过命令行轻松地直接测试它。

在我的例子中,我需要用命令行标志 --dir=调用一个应用程序(myapp.exe) ,比如:
myapp --dir=<path-to-desired-directory>.

由于我总是希望标志总是引用我从哪个目录调用应用程序,我可以制作一个批处理文件(mybat.bat) ,以自动捕获我的当前路径,并打开应用程序与它。

当 mybat.bat 包含以下内容时,mybat .可以工作:
myapp --dir=%1

这是伟大的,但能够停止 .甚至更好。
当我将内容更改为:
myapp --dir=%CD%