将换行符附加到要 "echo"ed 的变量

Appending newlines to a variable to be "echo"ed out

过去 12 年我一直在 Linux 工作,之前使用 Windows 和命令行,最近不得不恢复那些批处理文件技能,以便于使用/ 编辑实用程序。但是,我在找出如何使用换行符构建字符串变量时遇到了一些问题(相当于 Linux 的 echo -e "Line1\nLine2"

基本上我的实用程序会询问用户三个问题并检查输入的有效性。如果有效性失败,每个输入都有一个略有不同的“错误消息”。然后我检查 errMsg 变量是否包含任何内容,如果包含,它会列出来自 3 次有效性检查的整理错误消息。除了错误消息在一行之外,这一切都完美无缺,我想将每个错误放在它自己的行上。然后我“仅仅”在字符串中添加换行符......这就是这个问题的症结所在。

我使用 this link 作为参考点并使用基本字符串,新行按预期出现。但是,当我使用变量时,新行不会出现,我希望有人能向我解释原因。

我有以下代码片段

@echo off
setlocal enableextensions enabledelayedexpansion

set \n=^


set NL=^^^%\n%%\n%^%\n%%\n%

echo This does indeed put in a newline%NL%and this is the 2nd line
:: output follows:
::This does indeed put in a newline
::and this is the 2nd line

set var=Line1%NL%
set var=%var%Line2%NL%
:: output follows:
::Line1Line2

set errMsg=This would be the first custom error message%NL%
set errMsg=%errMsg%This would be the second custom error message%NL%
set errMsg=%errMsg%This would be the third custom error message%NL%
:: output follows
::This would be the first custom error messageThis would be the third custom error message

显然,此时我希望 Line1Line2 示例分为两行,然后最后一个示例将所有自定义错误消息分为三行(而实际上,它缺少第二个/中间的错误消息也是)

任何人都可以向我解释为什么这没有按预期工作吗?我想知道它是否与延迟扩展有关(我相信我需要:这个片段是一个更长的文件的一部分,它确实需要延迟扩展)。有没有更好的(或仅仅是替代的)方法来完成我正在寻找的东西?!

创建一个新的行变量是一个好的开始。但是你应该以不同的方式使用它。
百分比扩展不能很好地处理变量中的换行符,可以做到,但相当复杂。

但是延迟扩展完美地适用于任何角色

@echo off
setlocal EnableDelayedExpansion

(set \n=^
%=empty line=%
)

echo Line1!\n!Line2

set "multiline_var=First Line!\n!Second Line"

echo !multiline_var!

首先,延迟展开不会影响立即展开的new-lines(或者正确地说,line-feed个字符),因为你使用的是立即展开(%-)他们。

主要问题是 %-扩展发生得太早,当变量包含这样的内容时,这似乎会干扰对 line-breaks 的识别。

每次解析器扩展包含 line-breaks 的 % 变量时,line-break 后面的所有内容都会被忽略,因此必须转义它们,从而导致多种转义序列。这可以通过以下脚本进行演示:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

rem // Define a line-feed character:
set \n=^


rem // Define an escaped line-feed character:
set NL=^^^%\n%%\n%^%\n%%\n%
::rem // Redefine the escaped new-line character; it does not change, because the parser first expands `%`-variables before it recognises line-breaks in them:
::set NL=^^%NL%%NL%
rem // Define multi-escaped sequences needed when the same expanded value passes through the parser several times:
set NLNL=^^^^^^^^^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^%NL%%NL%^^%NL%%NL%
set NLNLNL=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^^^^^^^^^%NL%%NL%^^%NL%%NL%^^^^^^%NL%%NL%^^%NL%%NL%
::set NLNLNL=^^^^^^^^^^^^^^^^^^^^^^^^%NLNL%%NLNL%^^^^^^^^%NLNL%%NLNL%
echo  ---- DEFINITION ---- 
set NL
echo  -------------------- 

echo !\n! ***** IMMEDIATE EXPANSION ***** !\n!

rem // The more parser passes the more escaping is needed:
echo  -- VARIABLE CHECK -- 
set errMsg=This would be the first custom error message%NLNLNL%
set errMsg
set errMsg=%errMsg%This would be the second custom error message%NLNL%
set errMsg
set errMsg=%errMsg%This would be the third custom error message%NL%
set errMsg
echo  -- MESSAGE OUTPUT -- 
echo %errMsg%
echo  -------------------- 

echo !\n! ***** `CALL` EXPANSION ***** !\n!

echo  -- VARIABLE CHECK -- 
set errMsg=This would be the first custom error message%%NL%%
set errMsg
set errMsg=%errMsg%This would be the second custom error message%%NL%%
set errMsg
set errMsg=%errMsg%This would be the third custom error message%%NL%%
set errMsg
echo  -- MESSAGE OUTPUT -- 
call echo %errMsg%
echo  -------------------- 

echo !\n! ***** DELAYED EXPANSION ***** !\n!

echo  -- VARIABLE CHECK -- 
set errMsg=This would be the first custom error message!\n!
set errMsg
set errMsg=!errMsg!This would be the second custom error message!\n!
set errMsg
set errMsg=!errMsg!This would be the third custom error message!\n!
set errMsg
echo  -- MESSAGE OUTPUT -- 
echo !errMsg!
echo  -------------------- 

endlocal
exit /B

这是相关的命令提示符输出:

 ---- DEFINITION ----
NL=^


NLNL=^^^^^^^

^

^^^

^


NLNLNL=^^^^^^^^^^^^^^^

^

^^^

^

^^^^^^^

^

^^^

^


 --------------------

 ***** IMMEDIATE EXPANSION *****

 -- VARIABLE CHECK --
errMsg=This would be the first custom error message^^^^^^^

^

^^^

^


errMsg=This would be the first custom error message^^^

^

This would be the second custom error message^^^

^


errMsg=This would be the first custom error message^

This would be the second custom error message^

This would be the third custom error message

 -- MESSAGE OUTPUT --
This would be the first custom error message
This would be the second custom error message
This would be the third custom error message
 --------------------

 ***** `CALL` EXPANSION *****

 -- VARIABLE CHECK --
errMsg=This would be the first custom error message%NL%
errMsg=This would be the first custom error message%NL%This would be the second custom error message%NL%
errMsg=This would be the first custom error message%NL%This would be the second custom error message%NL%This would be the third custom error message%NL%
 -- MESSAGE OUTPUT --
This would be the first custom error message
This would be the second custom error message
This would be the third custom error message

 --------------------

 ***** DELAYED EXPANSION *****

 -- VARIABLE CHECK --
errMsg=This would be the first custom error message

errMsg=This would be the first custom error message
This would be the second custom error message

errMsg=This would be the first custom error message
This would be the second custom error message
This would be the third custom error message

 -- MESSAGE OUTPUT --
This would be the first custom error message
This would be the second custom error message
This would be the third custom error message

 --------------------

IMMEDIATE EXPANSION部分,当命令行多次通过解析过程时,需要复杂的转义序列来维护line-breaks。

<code>CALL EXPANSION 部分说明了一种更简单的方法,使用 call 命令,它引入了另一个解析阶段,它让文字字符串部分 %NL% 被扩展,它实际上包含在 errMsg 变量而不是 line-breaks 中。请注意,call 很慢,并且有 side-effects,如插入符-(^-)加倍和丢失 &|< > 在某些情况下。

最好的选择当然是使用延迟扩展,如 DELAYED EXPANSION 部分所示,因为这允许变量 errMsg 实际上包含 line-breaks 并安全地扩展它们而不用过早被解析器识别。