用于复制和修改包含重定向字符的文件的 Windows 批处理脚本

标签 windows batch-file scripting cmd

我们正在尝试将 bash shell 脚本转换为 Windows 批处理脚本。我们将这些脚本与我们的软件产品一起提供,我们不能假设客户将拥有或能够下载 sed/awk/cygwin 或任何其他非标准工具。因此,该脚本必须适用于 Windows 开箱即用的任何工具。最低目标平台是 Windows XP SP2。此脚本是从另一个批处理脚本调用的。

脚本的一部分需要在文件中搜索特定字符串并修改该字符串。在 bash 中,这很容易。我们在 Windows 批处理脚本中采用的方法是逐行遍历文件。如果某行不包含目标字符串,我们会按原样将其回显到临时文件。如果一行包含目标字符串,我们会将硬编码字符串回显到临时文件。

问题是输入文件的某些行包含小于号和大于号。如果我们在行周围加上引号,它们将原封不动地写入临时文件,但会被引用。

"-- this is a comment in the output .sql file"
"SELECT foo FROM bar WHERE something < 10;"
"--<SpecialInternalTagComment>"

如果我们使用 %~1 取消对它们的引用,那么 CMD.EXE 会尝试将 < 和 > 视为重定向符号,并在脚本遇到其中一行时产生错误,因为生成的命令将如下所示:

echo --<SpecialInternalTagComment> >> temp.file

这是我们目前拥有的。它生成文件内容,每行都用引号括起来。

:clean_install
    echo New installation >> %INSTALL_LOG%

    echo > %INSTALL_FOLDER%"\sql\oracle\table_maintenance_tmp.sql
    for /f "usebackq tokens=* delims=" %%A in (table_maintenance.sql) do (
       call :replace_width_and_write_line "%%A"
    )
    goto done

:replace_width_and_write_line
    echo %1 | find "&&TARGET_STRING" > NUL
    if %ERRORLEVEL% == 0 (
        echo    TABLE_PARTITION_WIDTH CONSTANT NUMBER := 7 ; >> %INSTALL_FOLDER%"\sql\oracle\table_maintenance_tmp.sql 
        goto :eof
    )
    echo %1 >> %INSTALL_FOLDER%"\sql\oracle\table_maintenance_tmp.sql
    goto :eof

问题是,如果字符串包含重定向符号,我们如何将字符串的内容不加引号回显到文件中?如果做不到,那么有没有另一种方法来实现我们最初的目标,即输入一个可能包含或不包含某个目标字符串的文件,并产生一个与原始文件相同的文件作为输出文件除了如果目标字符串存在,它会被一个新字符串替换?

我在 stackoverflow 上搜索过,最有用的两个问题是:
* How do you strip quotes out of an ECHO’ed string in a Windows batch file?
* Dealing with quotes in Windows batch scripts

注意:请不要推荐 Cygwin、sed、awk、Perl、Python、Ruby、unx 或 Windows XP 未附带的任何其他技术。这些答案将被否决。

谢谢,
铲子

最佳答案

我建议在这里使用 VBScript 来处理文件。默认情况下也包含它,并且字符串处理更不容易出错。

虽然有可能在打印行之前转义特殊字符。不过,这既乏味又缓慢。

首先,您需要将您的行放在一个环境变量中。使用引号避免任何特殊字符弄乱一切:

set "tmp=%~1"

请注意将引号放在完整的参数周围,而不仅仅是 = 之后的部分,否则您最终也会在变量中使用引号。

然后你就可以开始对特殊字符进行转义了,一个接一个:

set "tmp=%tmp:<=^<%"
set "tmp=%tmp:>=^>%"
set "tmp=%tmp:&=^&%"
set "tmp=%tmp:|=^|%"

等等

这应该可行,但操作环境变量非常慢,因此在大文件中这不会很有趣。

下面是我使用这些替代品的简短记录。但是,奇数个内嵌引号会导致失败,所以要小心:

> set "a=foo <bar> baz"

> set a
a=foo <bar> baz

> echo %a%
The system cannot find the file specified.

> set "a=%a:<=^<%"

> set a
a=foo ^<bar> baz

> set "a=%a:>=^>%"

> set a
a=foo ^<bar^> baz

> echo %a%
foo <bar> baz

不过,一般来说,我建议使用 VBScript,作为批处理文件的一种现成的替代方法,并且更强大,或者至少,在处理此类事情时不那么令人惊讶。

关于用于复制和修改包含重定向字符的文件的 Windows 批处理脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1308568/

相关文章:

android - 从eclipse/android环境生成项目/类图

windows - 在cmd中使用dir获取没有路径的文件夹名称

c# - 如何从 c# powershell 脚本执行中提取 $lastexitcode

php - 是否可以轻松地从另一个程序控制 mplayer?

windows - 文件系统上的 Mercurial Remote 而不是 http 服务器

c# - 如何从 Windows XP 下的程序中知道或更改 Windows 事件日志的大小?

windows - 抑制 Windows 命令行中的错误消息

batch-file - 在一行中计算一个确切的字符 - cmd

python - 将参数从批处理文件传递到 Python

shell - 转义字符串