67

我有一个简单的 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>
4

9 回答 9

136

使用"%~1". %~1单独删除周围的引号。但是,由于您不知道输入参数是否%1有引号,因此您应该确保"%~1"它们被肯定地添加。这在连接变量时特别有用,例如convert.exe "%~1.input" "%~1.output"

于 2010-12-08T14:43:00.247 回答
19

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

您的特定脚本通过使用 %1 而不是 "%1" 得到修复!!!

通过添加“echo on”(或摆脱 echo off),您可以很容易地发现它。

于 2009-01-23T16:10:32.387 回答
15

我认为 OP 的问题是他想做以下件事:

  • 传递可能包含空格的参数
  • 测试是否缺少参数

正如几位海报所提到的,要传递包含空格的参数,您必须用双引号将实际参数值括起来。

测试一个参数是否缺失,我一直学的方法是:

if "%1" == ""

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

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

这会导致“意外”错误。如果您改为使用

if %1 == ""

那么引用值不再发生错误。但在这种情况下,当值丢失时,测试不再起作用——它变成

if  == ""

要解决此问题,请在测试中使用任何其他字符(对 DOS 具有特殊含义的字符除外)而不是引号:

if [%1] == []
if .%1. == ..
if abc%1xyz == abcxyz
于 2009-05-05T16:29:25.177 回答
7

"%~1" 大部分时间都可以使用。但是,您需要注意以下几点:

  1. Windows NT 4.0 不支持它。您需要 Windows 2000 或更高版本。(如果您正在编写与旧操作系统兼容的脚本,请注意。)
  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在 Windows NT 4 中也不起作用。感谢这里的信息:http ://www.robvanderwoude.com/local.php )

于 2015-03-06T07:37:15.810 回答
5

如果您有带空格的路径,则必须用引号 (") 将其括起来。

不确定这是否正是您要问的?

于 2009-01-23T14:44:36.040 回答
2
@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""这意味着:

  • '空字符串' ( ""),
  • 后跟“c:\Program”,
  • 其次是“这里出乎意料”'Files\xxx',
  • 后跟一个空字符串 ( "")

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

于 2009-01-23T16:15:52.517 回答
2

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

于 2012-08-31T10:06:07.423 回答
0

假设您要通过在 C# 代码中执行批处理文件来备份数据库。这是一个完全有效的解决方案,可以处理路径内的空格。这适用于 Windows。我还没有用单声道测试它。

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%"
于 2021-01-18T13:34:27.733 回答
0

在特殊情况下,您希望始终默认为当前目录,或者,只有在未传入参数时才默认为当前目录,您可以使用%CD%.

正如在 Server Fault 上的这个答案中找到的那样:

Windows 在伪环境变量中维护当前目录%CD%

查看该帖子以获得一个很好的示例,以及如何通过命令行轻松地直接对其进行测试。

就我而言,myapp.exe我需要使用命令行标志调用一个应用程序 ( ) --dir=,例如:
myapp --dir=<path-to-desired-directory>

由于我一直希望标志始终引用我调用应用程序的目录,因此我可以制作一个批处理文件 ( mybat.bat) 来自动捕获我的当前路径,并使用它打开应用程序。

mybat .当 mybat.bat 具有以下内容时工作:
myapp --dir=%1

这很棒,但能够离开 .就更好了。
mybat当我将内容更改为:
myapp --dir=%CD%

于 2021-09-25T20:56:26.950 回答