我正在使用Windows命令行环境编写批处理文件脚本,想要将文件中每个文本实例(例如 "FOO")更改为另一个文本(例如 "BAR")。最简单的方法是什么?是否有任何内置函数可以使用?
我正在使用Windows命令行环境编写批处理文件脚本,想要将文件中每个文本实例(例如 "FOO")更改为另一个文本(例如 "BAR")。最简单的方法是什么?是否有任何内置函数可以使用?
这里的许多答案都帮助我找到了正确方向,但对我来说都不太合适,所以我将发布我的解决方案。
我使用的是预装 PowerShell 的 Windows 7。下面是我用来查找/替换文件中所有文本实例的脚本:
powershell -Command "(gc myFile.txt) -replace 'foo', 'bar' | Out-File -encoding ASCII myFile.txt"
简单解释:
powershell
是启动Windows 7中包含的powershell.exe的命令。-Command ""... ""
是传递给powershell.exe的命令行参数,其中包含要运行的命令。(gc myFile.txt)
读取myFile.txt
的内容(gc
是Get-Content
命令的简写)。-replace 'foo', 'bar'
只需运行替换命令,将foo
替换为bar
。| Out-File myFile.txt
将输出导入到文件myFile.txt
中。-encoding ASCII
防止将输出文件转录为Unicode,正如注释所指出的那样。PowerShell.exe应该已经是你的PATH语句的一部分了,但如果不是,你可以添加它。在我的机器上,它的位置是C:\WINDOWS\system32\WindowsPowerShell\v1.0
更新
显然,现代Windows系统已经内置了PowerShell,允许您直接访问它。
(Get-Content myFile.txt) -replace 'foo', 'bar' | Out-File -encoding ASCII myFile.txt
如果你使用支持 .Net 2.0 的 Windows 版本,我会建议你更换你的 shell。 PowerShell 可以让你在命令行中使用完整的 .Net 功能,内置了许多命令集。下面的示例将解决您的问题。我正在使用命令的完整名称,虽然还有更短的别名,但这可以让你通过搜索找到相应的命令。
(Get-Content test.txt) | ForEach-Object { $_ -replace "foo", "bar" } | Set-Content test2.txt
powershell -Command "(gc myFile.txt) -replace 'foo', 'bar' | sc myFile.txt"
。该命令将读取名为 myFile.txt
的文件,将其中所有的字符串 'foo'
替换为 'bar'
,然后将修改后的内容重新写入到 myFile.txt
文件中。 - Nigel Touch刚刚使用了FART("Find And Replace Text" 命令行实用程序):
这是一个优秀的免费软件,用于在大量文件中进行文本替换。
设置文件在SourceForge上。
使用示例:
fart.exe -p -r -c -- C:\tools\perl-5.8.9\* @@APP_DIR@@ C:\tools
该Perl发布版将预览需要在文件中递归执行的替换操作。
唯一的问题是,FART网站图标并不精美或优雅 ;)
更新于2017年(七年后),jagb在评论中指出了这篇2011年文章“简单的FART方式——查找和替换文本”来自Mikail Tunç
正如Joe Jobs在评论中所指出的(2020年12月),如果您想要替换&A
,则需要使用引号以确保&
不被shell解释:
fart in.txt "&A" "B"
/
和 '
时要小心,因为这种方法不适用于我们所有人,对我来说,在某些情况下它确实有效,但在某些文件上却没有效果,我不知道为什么... 我使用它将文本替换为其他文本和一个 /
。 - jagb替换 - 使用字符串替换来替换子字符串 描述:使用字符串替换功能将一个子字符串替换为另一个字符串。此处展示的示例将字符串变量str中所有出现的"teh"拼写错误替换为"the"。
set str=teh cat in teh hat
echo.%str%
set str=%str:teh=the%
echo.%str%
脚本输出:
teh cat in teh hat
the cat in the hat
参考链接: http://www.dostips.com/DtTipsStringManipulation.php#Snippets.Replace
创建文件replace.vbs:
Const ForReading = 1
Const ForWriting = 2
strFileName = Wscript.Arguments(0)
strOldText = Wscript.Arguments(1)
strNewText = Wscript.Arguments(2)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(strFileName, ForReading)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, strOldText, strNewText)
Set objFile = objFSO.OpenTextFile(strFileName, ForWriting)
objFile.Write strNewText 'WriteLine adds extra CR/LF
objFile.Close
要使用此修改后的脚本(我们将其称为replace.vbs),只需从命令提示符输入类似于以下命令:
cscript replace.vbs "C:\Scripts\Text.txt" "Jim " "James "
RegExp
。您可以使用它来使用正则表达式进行替换: With (New RegExp): strNewText = .Replace(strText, strOldText, strNewText): End With
。您可以使用 $1
, $2
...$9
获取前9个捕获组的文本。 - ToothbrushBatchSubstitute.bat
在dostips.com上提供了一个使用纯批处理文件进行搜索和替换的示例。
它使用了FOR
, FIND
和 CALL SET
的组合。
包含字符"&<>]|^
的行可能会被错误地处理。
注意 - 请务必查看本答案末尾的更新,以获取优秀的JREPL.BAT替代REPL.BAT的链接。
JREPL.BAT 7.0及以上版本通过/UTF
选项原生支持Unicode(UTF-16LE)以及包括UTF-8在内的任何其他字符集,使用ADO实现!
我编写了一个名为REPL.BAT的小型混合JScript /批处理实用程序,非常方便地通过命令行或批处理文件修改ASCII(或扩展ASCII)文件。这个纯粹的本地脚本不需要安装任何第三方可执行文件,它适用于从XP到现代Windows版本的任何操作系统。与纯批处理解决方案相比,它也非常快速。
REPL.BAT简单地读取stdin,执行JScript正则表达式搜索和替换,并将结果写入stdout。
以下是一个微不足道的示例,演示如何将test.txt中的foo替换为bar,假设REPL.BAT在当前文件夹中,或更好的是,在您的PATH中的某个位置:
type test.txt|repl "foo" "bar" >test.txt.new
move /y test.txt.new test.txt
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
::************ Documentation ***********
::REPL.BAT version 6.2
:::
:::REPL Search Replace [Options [SourceVar]]
:::REPL /?[REGEX|REPLACE]
:::REPL /V
:::
::: Performs a global regular expression search and replace operation on
::: each line of input from stdin and prints the result to stdout.
:::
::: Each parameter may be optionally enclosed by double quotes. The double
::: quotes are not considered part of the argument. The quotes are required
::: if the parameter contains a batch token delimiter like space, tab, comma,
::: semicolon. The quotes should also be used if the argument contains a
::: batch special character like &, |, etc. so that the special character
::: does not need to be escaped with ^.
:::
::: If called with a single argument of /?, then prints help documentation
::: to stdout. If a single argument of /?REGEX, then opens up Microsoft's
::: JScript regular expression documentation within your browser. If a single
::: argument of /?REPLACE, then opens up Microsoft's JScript REPLACE
::: documentation within your browser.
:::
::: If called with a single argument of /V, case insensitive, then prints
::: the version of REPL.BAT.
:::
::: Search - By default, this is a case sensitive JScript (ECMA) regular
::: expression expressed as a string.
:::
::: JScript regex syntax documentation is available at
::: http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
::: Replace - By default, this is the string to be used as a replacement for
::: each found search expression. Full support is provided for
::: substituion patterns available to the JScript replace method.
:::
::: For example, $& represents the portion of the source that matched
::: the entire search pattern, $1 represents the first captured
::: submatch, $2 the second captured submatch, etc. A $ literal
::: can be escaped as $$.
:::
::: An empty replacement string must be represented as "".
:::
::: Replace substitution pattern syntax is fully documented at
::: http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
::: Options - An optional string of characters used to alter the behavior
::: of REPL. The option characters are case insensitive, and may
::: appear in any order.
:::
::: A - Only print altered lines. Unaltered lines are discarded.
::: If the S options is present, then prints the result only if
::: there was a change anywhere in the string. The A option is
::: incompatible with the M option unless the S option is present.
:::
::: B - The Search must match the beginning of a line.
::: Mostly used with literal searches.
:::
::: E - The Search must match the end of a line.
::: Mostly used with literal searches.
:::
::: I - Makes the search case-insensitive.
:::
::: J - The Replace argument represents a JScript expression.
::: The expression may access an array like arguments object
::: named $. However, $ is not a true array object.
:::
::: The $.length property contains the total number of arguments
::: available. The $.length value is equal to n+3, where n is the
::: number of capturing left parentheses within the Search string.
:::
::: $[0] is the substring that matched the Search,
::: $[1] through $[n] are the captured submatch strings,
::: $[n+1] is the offset where the match occurred, and
::: $[n+2] is the original source string.
:::
::: Arguments $[0] through $[10] may be abbreviated as
::: $1 through $10. Argument $[11] and above must use the square
::: bracket notation.
:::
::: L - The Search is treated as a string literal instead of a
::: regular expression. Also, all $ found in the Replace string
::: are treated as $ literals.
:::
::: M - Multi-line mode. The entire contents of stdin is read and
::: processed in one pass instead of line by line, thus enabling
::: search for \n. This also enables preservation of the original
::: line terminators. If the M option is not present, then every
::: printed line is terminated with carriage return and line feed.
::: The M option is incompatible with the A option unless the S
::: option is also present.
:::
::: Note: If working with binary data containing NULL bytes,
::: then the M option must be used.
:::
::: S - The source is read from an environment variable instead of
::: from stdin. The name of the source environment variable is
::: specified in the next argument after the option string. Without
::: the M option, ^ anchors the beginning of the string, and $ the
::: end of the string. With the M option, ^ anchors the beginning
::: of a line, and $ the end of a line.
:::
::: V - Search and Replace represent the name of environment
::: variables that contain the respective values. An undefined
::: variable is treated as an empty string.
:::
::: X - Enables extended substitution pattern syntax with support
::: for the following escape sequences within the Replace string:
:::
::: \\ - Backslash
::: \b - Backspace
::: \f - Formfeed
::: \n - Newline
::: \q - Quote
::: \r - Carriage Return
::: \t - Horizontal Tab
::: \v - Vertical Tab
::: \xnn - Extended ASCII byte code expressed as 2 hex digits
::: \unnnn - Unicode character expressed as 4 hex digits
:::
::: Also enables the \q escape sequence for the Search string.
::: The other escape sequences are already standard for a regular
::: expression Search string.
:::
::: Also modifies the behavior of \xnn in the Search string to work
::: properly with extended ASCII byte codes.
:::
::: Extended escape sequences are supported even when the L option
::: is used. Both Search and Replace support all of the extended
::: escape sequences if both the X and L opions are combined.
:::
::: Return Codes: 0 = At least one change was made
::: or the /? or /V option was used
:::
::: 1 = No change was made
:::
::: 2 = Invalid call syntax or incompatible options
:::
::: 3 = JScript runtime error, typically due to invalid regex
:::
::: REPL.BAT was written by Dave Benham, with assistance from DosTips user Aacini
::: to get \xnn to work properly with extended ASCII byte codes. Also assistance
::: from DosTips user penpen diagnosing issues reading NULL bytes, along with a
::: workaround. REPL.BAT was originally posted at:
::: http://www.dostips.com/forum/viewtopic.php?f=3&t=3855
:::
::************ Batch portion ***********
@echo off
if .%2 equ . (
if "%~1" equ "/?" (
<"%~f0" cscript //E:JScript //nologo "%~f0" "^:::" "" a
exit /b 0
) else if /i "%~1" equ "/?regex" (
explorer "http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx"
exit /b 0
) else if /i "%~1" equ "/?replace" (
explorer "http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx"
exit /b 0
) else if /i "%~1" equ "/V" (
<"%~f0" cscript //E:JScript //nologo "%~f0" "^::(REPL\.BAT version)" "$1" a
exit /b 0
) else (
call :err "Insufficient arguments"
exit /b 2
)
)
echo(%~3|findstr /i "[^SMILEBVXAJ]" >nul && (
call :err "Invalid option(s)"
exit /b 2
)
echo(%~3|findstr /i "M"|findstr /i "A"|findstr /vi "S" >nul && (
call :err "Incompatible options"
exit /b 2
)
cscript //E:JScript //nologo "%~f0" %*
exit /b %errorlevel%
:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b
************* JScript portion **********/
var rtn=1;
try {
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) options+=args.Item(2).toLowerCase();
var multi=(options.indexOf("m")>=0);
var alterations=(options.indexOf("a")>=0);
if (alterations) options=options.replace(/a/g,"");
var srcVar=(options.indexOf("s")>=0);
if (srcVar) options=options.replace(/s/g,"");
var jexpr=(options.indexOf("j")>=0);
if (jexpr) options=options.replace(/j/g,"");
if (options.indexOf("v")>=0) {
options=options.replace(/v/g,"");
search=env(search);
replace=env(replace);
}
if (options.indexOf("x")>=0) {
options=options.replace(/x/g,"");
if (!jexpr) {
replace=replace.replace(/\\\\/g,"\\B");
replace=replace.replace(/\\q/g,"\"");
replace=replace.replace(/\\x80/g,"\\u20AC");
replace=replace.replace(/\\x82/g,"\\u201A");
replace=replace.replace(/\\x83/g,"\\u0192");
replace=replace.replace(/\\x84/g,"\\u201E");
replace=replace.replace(/\\x85/g,"\\u2026");
replace=replace.replace(/\\x86/g,"\\u2020");
replace=replace.replace(/\\x87/g,"\\u2021");
replace=replace.replace(/\\x88/g,"\\u02C6");
replace=replace.replace(/\\x89/g,"\\u2030");
replace=replace.replace(/\\x8[aA]/g,"\\u0160");
replace=replace.replace(/\\x8[bB]/g,"\\u2039");
replace=replace.replace(/\\x8[cC]/g,"\\u0152");
replace=replace.replace(/\\x8[eE]/g,"\\u017D");
replace=replace.replace(/\\x91/g,"\\u2018");
replace=replace.replace(/\\x92/g,"\\u2019");
replace=replace.replace(/\\x93/g,"\\u201C");
replace=replace.replace(/\\x94/g,"\\u201D");
replace=replace.replace(/\\x95/g,"\\u2022");
replace=replace.replace(/\\x96/g,"\\u2013");
replace=replace.replace(/\\x97/g,"\\u2014");
replace=replace.replace(/\\x98/g,"\\u02DC");
replace=replace.replace(/\\x99/g,"\\u2122");
replace=replace.replace(/\\x9[aA]/g,"\\u0161");
replace=replace.replace(/\\x9[bB]/g,"\\u203A");
replace=replace.replace(/\\x9[cC]/g,"\\u0153");
replace=replace.replace(/\\x9[dD]/g,"\\u009D");
replace=replace.replace(/\\x9[eE]/g,"\\u017E");
replace=replace.replace(/\\x9[fF]/g,"\\u0178");
replace=replace.replace(/\\b/g,"\b");
replace=replace.replace(/\\f/g,"\f");
replace=replace.replace(/\\n/g,"\n");
replace=replace.replace(/\\r/g,"\r");
replace=replace.replace(/\\t/g,"\t");
replace=replace.replace(/\\v/g,"\v");
replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
replace=replace.replace(/\\B/g,"\\");
}
search=search.replace(/\\\\/g,"\\B");
search=search.replace(/\\q/g,"\"");
search=search.replace(/\\x80/g,"\\u20AC");
search=search.replace(/\\x82/g,"\\u201A");
search=search.replace(/\\x83/g,"\\u0192");
search=search.replace(/\\x84/g,"\\u201E");
search=search.replace(/\\x85/g,"\\u2026");
search=search.replace(/\\x86/g,"\\u2020");
search=search.replace(/\\x87/g,"\\u2021");
search=search.replace(/\\x88/g,"\\u02C6");
search=search.replace(/\\x89/g,"\\u2030");
search=search.replace(/\\x8[aA]/g,"\\u0160");
search=search.replace(/\\x8[bB]/g,"\\u2039");
search=search.replace(/\\x8[cC]/g,"\\u0152");
search=search.replace(/\\x8[eE]/g,"\\u017D");
search=search.replace(/\\x91/g,"\\u2018");
search=search.replace(/\\x92/g,"\\u2019");
search=search.replace(/\\x93/g,"\\u201C");
search=search.replace(/\\x94/g,"\\u201D");
search=search.replace(/\\x95/g,"\\u2022");
search=search.replace(/\\x96/g,"\\u2013");
search=search.replace(/\\x97/g,"\\u2014");
search=search.replace(/\\x98/g,"\\u02DC");
search=search.replace(/\\x99/g,"\\u2122");
search=search.replace(/\\x9[aA]/g,"\\u0161");
search=search.replace(/\\x9[bB]/g,"\\u203A");
search=search.replace(/\\x9[cC]/g,"\\u0153");
search=search.replace(/\\x9[dD]/g,"\\u009D");
search=search.replace(/\\x9[eE]/g,"\\u017E");
search=search.replace(/\\x9[fF]/g,"\\u0178");
if (options.indexOf("l")>=0) {
search=search.replace(/\\b/g,"\b");
search=search.replace(/\\f/g,"\f");
search=search.replace(/\\n/g,"\n");
search=search.replace(/\\r/g,"\r");
search=search.replace(/\\t/g,"\t");
search=search.replace(/\\v/g,"\v");
search=search.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
search=search.replace(/\\B/g,"\\");
} else search=search.replace(/\\B/g,"\\\\");
}
if (options.indexOf("l")>=0) {
options=options.replace(/l/g,"");
search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
if (!jexpr) replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("b")>=0) {
options=options.replace(/b/g,"");
search="^"+search
}
if (options.indexOf("e")>=0) {
options=options.replace(/e/g,"");
search=search+"$"
}
var search=new RegExp(search,options);
var str1, str2;
if (srcVar) {
str1=env(args.Item(3));
str2=str1.replace(search,jexpr?replFunc:replace);
if (!alterations || str1!=str2) if (multi) {
WScript.Stdout.Write(str2);
} else {
WScript.Stdout.WriteLine(str2);
}
if (str1!=str2) rtn=0;
} else if (multi){
var buf=1024;
str1="";
while (!WScript.StdIn.AtEndOfStream) {
str1+=WScript.StdIn.Read(buf);
buf*=2
}
str2=str1.replace(search,jexpr?replFunc:replace);
WScript.Stdout.Write(str2);
if (str1!=str2) rtn=0;
} else {
while (!WScript.StdIn.AtEndOfStream) {
str1=WScript.StdIn.ReadLine();
str2=str1.replace(search,jexpr?replFunc:replace);
if (!alterations || str1!=str2) WScript.Stdout.WriteLine(str2);
if (str1!=str2) rtn=0;
}
}
} catch(e) {
WScript.Stderr.WriteLine("JScript runtime error: "+e.message);
rtn=3;
}
WScript.Quit(rtn);
function replFunc($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) {
var $=arguments;
return(eval(replace));
}
重要更新
我已停止开发 REPL.BAT,并将其替换为 JREPL.BAT。这个新的实用工具拥有 REPL.BAT 的所有功能,还有更多:
与往常一样,完整的文档嵌入在脚本中。
原始简单解决方案现在甚至更加简单:
jrepl "foo" "bar" /f test.txt /o -
JREPL.BAT的当前版本可在DosTips上获得。阅读该主题中所有后续帖子,以查看使用示例和开发历史。
WScript.StdIn.ReadAll()
错误的方法。请参见http://www.dostips.com/forum/viewtopic.php?p=36033#p36033。 - dbenham使用 fnr
工具。它比 fart
有一些优点:
在此处下载 FNR:http://findandreplace.io/?z=codeplex
用法示例:
fnr --cl --dir "<目录路径>" --fileMask "hibernate.*" --useRegEx --find "查找字符串表达式" --replace "替换字符串"
Find&Replace
的支持目前已暂停。 - Andrey Kazaksed -i -b -e 's/FOO/BAR/g' \
find . -name *.txt`` -i -- 直接编辑文件;-b -- 不处理 CR+LF - 如果没有这个选项,CR+LF 将被转换为 LF - Alexey Vishentsev我知道我有点晚了。。
个人而言,我喜欢这个解决方案: - http://www.dostips.com/DtTipsStringManipulation.php#Snippets.Replace
我们还广泛使用去重函数,通过SMTP每天发送约500封电子邮件: - https://groups.google.com/forum/#!topic/alt.msdos.batch.nt/sj8IUhMOq6o
这两个方法都能够原生地工作,不需要额外的工具或实用程序。
REPLACER:
DEL New.txt
setLocal EnableDelayedExpansion
For /f "tokens=* delims= " %%a in (OLD.txt) do (
Set str=%%a
set str=!str:FOO=BAR!
echo !str!>>New.txt
)
ENDLOCAL
去重程序(注意ABA号码使用-9):
REM DE-DUPLICATE THE Mapping.txt FILE
REM THE DE-DUPLICATED FILE IS STORED AS new.txt
set MapFile=Mapping.txt
set ReplaceFile=New.txt
del %ReplaceFile%
::DelDupeText.bat
rem https://groups.google.com/forum/#!topic/alt.msdos.batch.nt/sj8IUhMOq6o
setLocal EnableDelayedExpansion
for /f "tokens=1,2 delims=," %%a in (%MapFile%) do (
set str=%%a
rem Ref: http://www.dostips.com/DtTipsStringManipulation.php#Snippets.RightString
set str=!str:~-9!
set str2=%%a
set str3=%%a,%%b
find /i ^"!str!^" %MapFile%
find /i ^"!str!^" %ReplaceFile%
if errorlevel 1 echo !str3!>>%ReplaceFile%
)
ENDLOCAL
谢谢!