从 Windows 批处理 (.bat) 脚本中回显带有 Unix 行尾的文本

Posted

技术标签:

【中文标题】从 Windows 批处理 (.bat) 脚本中回显带有 Unix 行尾的文本【英文标题】:Echo text with Unix line endings from a Windows batch (.bat) script 【发布时间】:2017-04-09 18:24:28 【问题描述】:

假设我有以下批处理脚本:

For ... DO (
SET VAL=%%B
IF defined VAL echo %%A=%%B >> %OUTPUT_FILEPATH%
)

如何让echo 使用 Unix(仅换行)换行符输出?

或者,我可以按原样编写文件,然后从批处理脚本中转换它吗? (某种查找 /r/n 并用 /n 替换?如果是,我该怎么做?)

我想要一个独立的解决方案(即不涉及下载额外实用程序的解决方案,并且可以从批处理脚本本身 [Windows 7] 中完成)。

【问题讨论】:

我很惊讶我在 SO 的某个地方找不到这个问题 将文本文件转换为 Unix 风格的换行符实际上只是输出每一行而不带尾随换行符,然后是显式输出的换行符。因此,在搜索“没有换行符的回声”和“换行符”之类的内容时,您可能会发现一些有用的东西...... 网络上有很多关于将 Windows 文本文件转换为 unix 的内容。如果你有我的JREPL.BAT regular expression text processing utility,那么你可以正常写入文件,然后使用call jrepl "^" "" /u /f yourFile.txt /o -。或者,您可以使用管道直接以 unix 格式写入文件:yourCommandThatGeneratesFile | jrepl "^" "" /u /o yourFile.txt @dbenham:我不明白你的jrepl "^" "" ... 是如何工作的。 "^" 正则表达式是匹配 positionanchor;它不匹配字符(所以它不能消除它们),并且在任何情况下,它都匹配行的开头,而不是所需的结尾... @Aacini - 这有点像 hack。查找/替换对故意没有效果。重要的一点是/U 选项,它使用\n 终止符而不是\r\n 写入所有行。我只需要一个非破坏性的查找/替换对。下载 JREPL 只是为了将文本转换为 unix 形式是可笑的。但对于许多其他情况来说,它是一个有用的工具,如果你碰巧已经拥有它,那么它可以成为进行这种转换的有效工具。我将 JREPL 解决方案写成评论而不是答案,正是因为它是一个 hack。 【参考方案1】:

如果你可以使用 PowerShell,你可以像这样生成一个 Unix 换行符:

PowerShell -Command Write-Host

您可以将此与 SET /P 技巧结合使用,以输出不带换行符的文本并手动添加换行符。例如:

( ECHO | SET /P="Hello World!" & PowerShell -Command Write-Host ) > output.txt

在此之后,output.txt 将包含文本 Hello World!附加一个 0x0a 字符。

【讨论】:

【参考方案2】:

取自Macros with parameters appended

格式化很棘手​​,但试试

set ^"LF=^

^" Don't remove previous line & rem line feed (newline)
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"& rem Define newline with line continuation

For ... DO (
SET VAL=%%B
IF defined VAL <nul set/P^=%%A=%%B%\n%>> %OUTPUT_FILEPATH%
)

或者,为了避免第一行之后的前导空格:

<nul set/P^=%%A=%%B%\n%^>> %OUTPUT_FILEPATH%

【讨论】:

tricky 可能是一个很好的轻描淡写......你有没有机会在你的答案中扩展它的作用? @simonalexander2005 抱歉,不是我的母语。根据%%A%%B 中的内容,可能会有很多字符需要转义,例如set/p ^= set/P^= 中的= 无需转义。将语法更改为set /P ="%%A=%%B%\n%",这样(周围的)引号就不会丢失了。但是,前导空格总是会丢失。请注意,前导 = 符号会导致语法错误。实际上没有使用set /P 的安全方法,但还有其他方法——参见this answer。或者你切换到另一种语言... @simonalexander2005 - 可以在***.com/a/6379861/1012053 找到对%\n% 的更好解释(jeb 将其称为%NL%。)。 &lt;nul set /p=... 是一种常用的 hack,用于编写文本末尾没有换行符 but it has limitations。 @dbenham 谢谢,你的 cmets 总是有新的东西!不错的帖子阅读!【参考方案3】:

执行这种转换的合适方法不是通过批处理文件,而是使用另一种编程语言,如 JScript;这样,转换过程既快速又可靠。但是,您不需要数百行程序来实现像这个一样简单的替换。下面的两行批处理文件做这个转换:

@set @a=0 /* & cscript //nologo //E:JScript "%~F0" < input.txt > output.txt & goto :EOF */

WScript.Stdout.Write(WScript.Stdin.ReadAll().replace(/\r\n/g,"\n"));

编辑:我对原始代码进行了修改,允许以标准方式在批处理部分中包含更多命令。

@set @a=0 /*

@echo off
set "OUTPUT_FILEPATH=C:\Path\Of\The\File.txt"
cscript //nologo //E:JScript "%~F0" < "%OUTPUT_FILEPATH%" > output.txt
move /Y output.txt "%OUTPUT_FILEPATH%"

goto :EOF */

WScript.Stdout.Write(WScript.Stdin.ReadAll().replace(/\r\n/g,"\n"));

第一行是从 JScript 代码中隐藏 cscript 命令的技巧,因此编译这个 hybrid .BAT 文件不会出现错误。

在 JScript 代码中:WScript.Stdin.ReadAll() 读取整个重定向的输入文件;如果文件巨大,这可能会导致问题。 replace 方法使用正则表达式来识别要替换的文本并将第二个字符串放在其位置;您可以在this link 阅读有关此主题的进一步说明。 WScript.Stdout.Write 只需从替换中获取输出并将其发送到屏幕。简单!不是吗? ;-)

【讨论】:

+1,但我对“正确的方式”这句话不太确定?!我宁愿看到像“明智的方式”这样的短语,很难说有效的批处理方法是“错误的”。但是我也会使用 JScript,很可能是通过 JREPL,因为它已经在我的技巧库中。我更喜欢使用行处理,因为 JScript 被限制为它可以读入单个字符串的最大大小。一次读取一行几乎可以消除大小问题。 @dbenham:嗯,有时我不会选择最好的术语。我改成“合适的方式”... 您说“将其发送到屏幕” - 我将如何将其放入我的输出文件(与读取的文件相同?)?你能举一个特定于我的场景的例子吗?所以我有一个文件(存储在 %OUTPUT_FILEPATH% 中) - 然后我将如何用你的方法替换该文件中的结尾? 正如您在代码中看到的那样,&gt; output.txt 部分将 JScript 的输出“到屏幕”重定向到“output.txt”文件中,因此您只需添加一个move /Y output.txt %OUTPUT_FILEPATH% 命令之后......我相应地修改了代码。

以上是关于从 Windows 批处理 (.bat) 脚本中回显带有 Unix 行尾的文本的主要内容,如果未能解决你的问题,请参考以下文章

在批处理脚本中回显到多个文件

如何从另一个 Windows 批处理脚本调用一个 Windows 批处理脚本并在两者中延迟扩展

Windows-执行python脚本(bat批处理)

Windows-执行python脚本(bat批处理)

错误记录Windows 系统 bat 脚本报错 ( Java 生成 bat 脚本乱码处理 | 输出 GB2312 字符串 | Windows 中的换行时 )

windows设置SpringBoot程序(bat脚本)开机自启