我们正在尝试将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会尝试处理&lt;和&gt;作为重定向符号,并在脚本遇到其中一行时产生错误,因为生成的命令将是这样的:
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一起提供的技术。这些答案将被否决。
谢谢,
shoover
答案 0 :(得分:2)
我建议在这里使用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作为批处理文件的一种随时可用的替代方案,并且在处理此类事情时更加强大,或者至少不那么令人惊讶。
答案 1 :(得分:0)
您可以使用edlin。
“它的持久性可能是 事实证明它可以 调用自动执行小 通过管道修改文本文件 它的命令脚本 标准输入。“
但请注意,它在64位版本上不可用 Windows和行长度限制为253个字符。
答案 2 :(得分:0)
cscript是为Windows安装的标准组件。 http://en.wikipedia.org/wiki/Windows_Script_Host
下面是一个清除正则表达式匹配的文本行的脚本。可以调整脚本以添加搜索rgx和替换文本的命令行参数。
/*
One part of the script needs to search through a file for a particular string and modify that string.
In bash, this is easy. The approach we are taking in the Windows batch script is to walk through the
file, line by line. If a line does not contain the target string, we echo it to a temp file as-is.
If a line contains the target string, we echo a hardcoded string to the temp file.
*/
/**
* Usage: type <in.file> | cscript //Nologo test.js > <out.file>
*/
function main() {
var rgxScrubMatch = /<SpecialInternalTagComment>/;
var replacement = "safe text";
scrubLines(rgxScrubMatch, replacement, WScript.StdIn, WScript.StdOut);
}
main();
/**
* Will echo back line
*
* @param rgxScrubMatch uses replacement on match
* @param replacement string to replace entire line that matches
* @param input input stream
* @param output output stream
* @return undefined
*/
function scrubLines(rgxScrubMatch, replacement, input, output) {
while(!input.AtEndOfStream) {
var line = input.ReadLine();
if(rgxScrubMatch.test(line)) {
output.Write(replacement + "\r\n");
} else {
output.Write(line + "\r\n");
}
}
}