通过 Windows 批处理文件将长命令拆分成多行

981

如何在批处理文件中将长命令拆分为多行?

7个回答

1216

可以使用符号^来分割长行,只要记住符号和随后的换行符号都会完全被移除。所以,如果你在分割行的位置需要有一个空格,就需要包含一个空格。(以下链接提供更多信息。)

示例:

copy file1.txt file2.txt

将被书写为:

copy file1.txt^
 file2.txt

138
如果在命令文本前面和 ^ 后面加上一个空格,你就可以在下一行开始而不需要空格。 - Joseph Daigle
4
不,你可以随时添加[SPACE]+[^]和两个空行,以创建总共2个换行符,当它被“echo”时。 - James K
29
当使用脱字符时,为了安全起见,请**_始终_以空行结束**,请参阅Simple carat in batch file consumes all memory - matt wilkie
4
@GavinMiller说:"在新的一行中,在复制和file1.txt后加入插入符号^将不起作用"。这是不正确的。你可以在任何地方分割文本,包括单词中间,例如co^␍py ^␍file1 ^␍file2。我建议您删除您的评论以避免混淆,尤其是因为这个问题非常受欢迎。 - Borodin
11
这里需要注意的是,^ 必须是行末最后一个字符 - 也就是说,后面不能有空格。我曾经因为这个问题苦恼了很久,后来发现在我使用的编辑器中,脱字符后面还有一堆空格,但并不容易看出来。 - GregHNZ
显示剩余7条评论

342

插入符号的规则是:

在行末使用插入符号(^),会将下一行添加到当前行,被添加行的第一个字符将被转义。

可以多次使用插入符号,但是整行字符数不能超过最大长度限制,约为8192个字符(适用于Windows XP,Windows Vista和Windows 7)。

echo Test1
echo one ^
two ^
three ^
four^
*
--- Output ---
Test1
one two three four*

echo Test2
echo one & echo two
--- Output ---
Test2
one
two

echo Test3
echo one & ^
echo two
--- Output ---
Test3
one
two

echo Test4
echo one ^
& echo two
--- Output ---
Test4
one & echo two
为了禁止转义下一个字符,您可以使用重定向。
重定向必须紧挨着脱字符之前。 但是,在脱字符之前进行重定向存在一种奇特情况。
如果在脱字符处放置一个标记,则该标记会被删除。
echo Test5
echo one <nul ^
& echo two
--- Output ---
Test5
one
two


echo Test6
echo one <nul ThisTokenIsLost^
& echo two
--- Output ---
Test6
one
two

而且还可以在字符串中嵌入换行符:

setlocal EnableDelayedExpansion
set text=This creates ^

a line feed
echo Test7: %text%
echo Test8: !text!
--- Output ---
Test7: This creates
Test8: This creates
a line feed

空行对于成功很重要。只有在延迟扩展时才起作用,否则在换行符后面忽略行的其余部分。

它有效的原因是行末的插入符号会忽略下一个换行符并转义下一个字符,即使下一个字符也是换行符(回车符在此阶段始终被忽略)。


6
问题是,我们是否应该支持一个不遵循规则的低效工具(有人称之为浏览器,但它并不是),还是应该转向使用浏览器? - jeb
2
我在我的值周围使用了双引号,例如set var="text here ^ ",但它不起作用。去掉双引号就可以了。 - rjt
1
@jeb,写了一个失败的cmd脚本示例,但后来发现了这个问题:https://dev59.com/X2445IYBdhLWcg3w6eNo - rjt
1
如果下一行以引号开头,则此方法无效:copy ^[newline]"file1.txt" ^[newline]"file2.txt" 无法正常工作!我不得不添加一个空格:copy ^[newline] "file1.txt" ^[newline] "file2.txt" - Alexander Gelbukh
1
@AlexanderGelbukh 这是预期的行为,描述为 ...附加行的第一个字符将被转义。 您可以使用空格或在 要抑制下一个字符的转义,您可以使用重定向。... 中描述的解决方案。 - jeb
显示剩余2条评论

123

你可以使用插入符号 (^) 来分隔长行,但请记住,插入符号和其后的换行符 将被完全删除,因此如果您将其放在需要空格的位置(例如参数之间),请确保同时包含空格(可以在 ^ 前面或下一行的开头添加空格 —— 后者的选择可能有助于使它更清晰地表示为续行)。

⚠ 注意:下一行的第一个字符是转义的。因此,如果它带有任何特殊含义(如 &|),那么这个含义将丢失,并且它将被解释为纯文本字符(请参见底部的最后一个示例)。

示例:(在 Windows XP 和 Windows 7 上测试通过)

xcopy file1.txt file2.txt

可以写成:


xcopy^
 file1.txt^
 file2.txt

或者

xcopy ^
file1.txt ^
file2.txt

或者甚至更好

xc^
opy ^
file1.txt ^
file2.txt

上述方法之所以有效,是因为xc^之间没有空格,并且下一行开头也没有空格。因此,当您删除^和换行符时,就会得到xcopy

为了提高可读性和代码的健壮性,最好只在参数之间断开(确保包括空格)。

一定要注意,在批处理文件的结尾不要使用^,因为那里可能会有一个主要问题(详情请点击此处)

以下是下一行开始时字符转义的示例:

xcopy file1.txt file2.txt ^
& echo copied successfully

这样做是行不通的,因为&会被转义并失去其特殊含义,从而将“file1.txt file2.txt & echo copied successfully”全部作为参数发送给xcopy,导致错误(在此示例中)。

为了规避这个问题,在下一行开头添加一个空格

(这基本上是Wayne's answer的重写,但消除了关于插入符的混淆。所以我把它发布为CW。我不介意编辑答案,但完全重写它们似乎不合适。)


26

多个命令可以被放在括号中并分散在多行上;所以像echo hi && echo hello这样的命令可以像这样放置:

多个命令可以被放在括号中并分散在多行上;所以像echo hi && echo hello这样的命令可以像这样放置:

( echo hi
  echo hello )

变量也可以帮助:

set AFILEPATH="C:\SOME\LONG\PATH\TO\A\FILE"
if exist %AFILEPATH% (
  start "" /b %AFILEPATH% -option C:\PATH\TO\SETTING...
) else (
...

我注意到尖号符号 (^) 在 if 条件语句中只有当存在空格时才会被识别:

if exist ^

1
cmd1.bat && cmd2.bat 这一行与括号形式不同:仅当 cmd1.bat 成功执行(而且没有设置 %errorcode%)时,才会执行 cmd2.bat。后者则是无条件执行。有点出乎意料的是(至少对我来说),显然你不能在换行前使用两者的组合,即在行末添加 && - Paul Michalik
(回车) (echo <换行符> 你好) 结果为空行。 - basickarl
最佳和最干净的答案! 插入符在正则表达式中很丑陋且有问题。 - neoscribe

15

然而,似乎在for循环的值的中间进行分割并不需要使用插入符(实际上尝试使用插入符会被视为语法错误)。例如,

for %n in (hello
bye) do echo %n

请注意,即使在“hello”之后或在“bye”之前也不需要空格。

1
当然,这是for语法的一部分:在“for-set”中元素的分隔符为 空格、逗号、分号、等号、制表符和换行符。 - Aacini
但是如果“do”部分包含多个/嵌套的“if-else”语句呢? - Vicky Dev
然后,您可以使用括号将语句括起来,如下所示:for %n in (hello bye) do ( echo %n echo %n ) - Mohammed Safwat
这是一种可能的方法,但您首先需要将所有项目存储在一行中,并执行一次。 - npocmaka

10

当我搜索“如何分割长的DOS批处理文件行”时,我没有找到如何分割包含长引用文本的内容。

实际上,以上的答案已经覆盖了这一点,但并不明显。使用Caret来转义它们。

例如:

myprog "needs this to be quoted"

可以写成:

myprog ^"needs this ^
to be quoted^"

但要注意,在以插入符号结尾的行后开始一行,因为它将输出为插入符号..?:

echo ^"^
needs this ^
to be quoted^
^"

-> "需要将此内容引用^"


您不需要转义最后一个引号。在新行中第一列的插入符(或任何其他特殊字符)将通过多行插入符进行转义。 - jeb
好主意! :) ... 我正在使用它来分割非常长的ffmpeg '-vf'参数,效果很棒。 - Simon H

8

虽然使用carret是执行此操作的首选方式,但以下是一种使用宏构建命令的方法,命令将由传递的参数构造:

@echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
set "{{=setlocal enableDelayedExpansion&for %%a in (" & set "}}="::end::" ) do if "%%~a" neq "::end::" (set command=!command! %%a) else (call !command! & endlocal)"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

%{{%
    echo
    "command"
    written
    on a
    few lines
%}}%

在没有尖括号的情况下,命令更易读取,但是使用特殊符号例如括号、重定向等会破坏其结构。因此,在更简单的情况下,您可以这样做。不过,您仍然可以将参数用双引号括起来。


5
这就是黑魔法或牙买加巫术的样子。 - Ярослав Рахматуллин

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接