如何在Windows命令行环境下查找并替换文件中的文本?

605

我正在使用Windows命令行环境编写批处理文件脚本,想要将文件中每个文本实例(例如 "FOO")更改为另一个文本(例如 "BAR")。最简单的方法是什么?是否有任何内置函数可以使用?

30个回答

435

这里的许多答案都帮助我找到了正确方向,但对我来说都不太合适,所以我将发布我的解决方案。

我使用的是预装 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的内容(gcGet-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

80
注意,这个指令可能会把文件转码为Unicode编码。你可以加上"-encoding ASCII"或者"UTF8"来手动指定编码。同时要注意,如果你选择了UTF8,它可能会在原始文件的开头添加一个字节顺序标记。 - Wyck
84
@Wyck 我花了一些时间才弄清楚在哪里放置“-encoding ASCII”。对于未来需要它的任何人,应该是“Out-File -encoding ASCII myFile.txt”。 - Reese
18
我需要使用“Set-Content”代替“Out-File”,这是我唯一需要更改的东西。 - kurtzmarc
9
这个方法可行,但即使是在一个很短的文件列表上表现也非常糟糕。 - jsuddsjr
33
请注意,替换标记(在本例中为“foo”)被视为正则表达式。如果您在其中包含任何特殊字符(例如 [ ] ),则需要在其前面添加反斜杠(\)进行转义。 - J W
显示剩余16条评论

187

如果你使用支持 .Net 2.0 的 Windows 版本,我会建议你更换你的 shell。 PowerShell 可以让你在命令行中使用完整的 .Net 功能,内置了许多命令集。下面的示例将解决您的问题。我正在使用命令的完整名称,虽然还有更短的别名,但这可以让你通过搜索找到相应的命令。

(Get-Content test.txt) | ForEach-Object { $_ -replace "foo", "bar" } | Set-Content test2.txt

14
我可以看到PowerShell有能力实现这个功能。但是我该如何让它从批处理文件(例如:myProc.bat)中运行? - Pablo Venturino
3
@Pablo,请使用powershell.exe,并将ps命令包装为单个参数。 - lubos hasko
61
回答确实被接受了,但它并不是对指定问题的答案。 - baash05
31
如果你尝试将内容保存到同一个文件中,这个操作会因文件正在被使用而失败。你需要修改PowerShell命令为:(Get-Content test.txt) | ForEach-Object { $_ -replace "foo", "bar" } | Set-Content test.txt,这样可以避免出错。 - BigMomma
9
请看 @Rachel 给出的答案:powershell -Command "(gc myFile.txt) -replace 'foo', 'bar' | sc myFile.txt"。该命令将读取名为 myFile.txt 的文件,将其中所有的字符串 'foo' 替换为 'bar',然后将修改后的内容重新写入到 myFile.txt 文件中。 - Nigel Touch
显示剩余16条评论

183

刚刚使用了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" 

23
很酷的是它只有一个exe文件,没有依赖关系,没有小字条款,超级易于部署。 - Serge Wautier
2
非常轻量级且易于使用,但我希望它能打印出替换发生的确切位置。无法看到这一点让我感到不安。 - William Niu
4
谢谢,很完美。应该成为标准的dos工具之一并且运行得很好。然而,“-p”选项不会显示它将要做出多少更改,总是报告0,这让我困惑了几分钟。 - sradforth
4
我知道这是一个非常古老的问题,但我找到了更多信息,希望对Stack Overflow的用户有所帮助。这里有另外一个关于FART的链接,其中对产品进行了很好的解释:FART explaned @emtunc.org,还可以在这里找到另外一个页面:FART。请注意,在替换 /' 时要小心,因为这种方法不适用于我们所有人,对我来说,在某些情况下它确实有效,但在某些文件上却没有效果,我不知道为什么... 我使用它将文本替换为其他文本和一个 / - jagb
1
查找和替换文本v1.99b: fart --c-style --quiet --preview "out.txt" "\/" "/" 将输入文件内容输出到stdio / stderr,而不是为25 MB文件显示替换信息。在https://sourceforge.net/p/fart-it/bugs/15上打开了一个错误票据。 - Andrey Kazak
显示剩余7条评论

145

替换 - 使用字符串替换来替换子字符串 描述:使用字符串替换功能将一个子字符串替换为另一个字符串。此处展示的示例将字符串变量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


33
SED 命令的建议更好吗?这似乎是它们所有答案中最简单的,并且不需要安装任何东西。 - DonBecker
5
这里能进行任何模式匹配吗?通配符、正则表达式等? - Benbob
32
“sed 建议更好在哪里?” - sed 和类似的实用程序操作文件;此代码片段省略了从输入文件读取行并写入输出文件的重要步骤,同时确保正确处理文件中的任何特殊字符。 - Joe
8
@Asad,是的,那是真的。原帖是在询问文件,但实际上这也适用于不一定是文件的流。但我想说的是,这个答案是有缺陷的,因为它没有涉及从流中读取/写入和处理特殊字符。 - Joe
4
@Bill,如何将变量用作替换文本?例如,我有一个变量中的值和一个包含某些分隔符的字符串。使用“set str =%str:“##”=%varValue%%”不起作用。有什么解决方法吗? - MalTec
显示剩余5条评论

63

创建文件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 "


这很不错,它允许使用正则表达式吗? - user280109
3
是的,VBScript支持RegExp。您可以使用它来使用正则表达式进行替换: With (New RegExp): strNewText = .Replace(strText, strOldText, strNewText): End With。您可以使用 $1, $2...$9 获取前9个捕获组的文本。 - Toothbrush
3
VBScript经常被忽视(并受到诟病),但它可以在所有Windows平台上使用,非常易读且具有非常强大的功能。+1 - zelanix
1
@user280109,你刚刚给出了命令,但我想要替换(不区分大小写)。你能提供相应的命令吗? - Ajmal PraveeN
谢谢,这个脚本非常棒,我喜欢你的前缀(str和obj单词),我也是这样做的,虽然它已经有些老了,但它仍然很好用,可以让代码更易读。 - Ali Poustdouzan
你能在字符串中转义双引号吗?例如: cscript replace.vbs "C:\Scripts\Text.txt" "Jim says "hi" to you " "James says "hy" to you ",结果将是:Jim says "hi" to you --> James says "hy" to you。 - tim99

53

9
我必须质疑一个代码片段网站的实用性,因为它的使用条款禁止复制任何代码(“未经该网站所有者明确书面许可,您不得以任何形式分发dostips.com提供的任何信息。”)。 - Gilles 'SO- stop being evil'
1
我同意他们的条款很令人困惑,他们还说“在dostips.com域名下提供的信息希望是有用的”,因此我的假设是他们乐意让人们复制代码以解决问题。 我不确定我是否曾经阅读过任何条款和条件并感到满意... - morechilli
5
太棒了。我喜欢不需要下载其他东西就可以完成的答案。 - Ruairi O'Brien
我也喜欢不涉及外部工具的解决方案,但不幸的是,当我尝试运行这个批处理时,我一直收到“find: invalid predicate `” 的错误提示。现在真的没有时间调试它了。 - James John McGuire 'Jahmic'
3
“find: invalid predicate `'"”错误是由于我系统上的外部“find”实用程序引起的。一旦移除,问题就解决了。 - James John McGuire 'Jahmic'

52

注意 - 请务必查看本答案末尾的更新,以获取优秀的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

JScript的正则表达式功能非常强大,特别是替换文本能够引用搜索文本中捕获的子字符串。
我在实用程序中包含了许多选项,使其非常强大。例如,结合“M”和“X”选项可以修改二进制文件!“M”多行选项允许跨多行进行搜索。 “X”扩展替换模式选项提供了转义序列,使得可以将任何二进制值包含到替换文本中。
整个实用程序本来可以编写为纯JScript,但混合批处理文件消除了每次想要使用实用程序时都需要显式指定CSCRIPT的需要。
这里是REPL.BAT脚本。完整的文档已嵌入到脚本中。
@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 的所有功能,还有更多:

  • 通过本地 CSCRIPT Unicode 功能支持 Unicode UTF-16LE,通过 ADO 支持任何其他字符集(包括 UTF-8)。
  • 直接从文件读取/写入文件:无需使用管道、重定向或 move 命令。
  • 包含用户提供的 JScript。
  • 类似于 Unix tr 的翻译功能,不仅支持正则表达式搜索,还支持 JScript 替换。
  • 丢弃不匹配的文本。
  • 在输出行前缀中添加行号。
  • 等等...

与往常一样,完整的文档嵌入在脚本中。

原始简单解决方案现在甚至更加简单:

jrepl "foo" "bar" /f test.txt /o -

JREPL.BAT的当前版本可在DosTips上获得。阅读该主题中所有后续帖子,以查看使用示例和开发历史。


@dbenham - +1。这是一个巧妙的方法,它也会在其他几个任务中派上用场。感谢您发布它。 - b w
编辑 - 更新代码到版本3.3:如果还使用S,选项A现在可以与M组合使用。还添加了新的帮助选项/?REGEX和/?REPLACE,可以自动在您的浏览器中打开相关的微软文档。 - dbenham
编辑 - 更新代码至版本4.0。添加选项N以启用读取包含NULL字节的二进制文件。这是一个解决WScript.StdIn.ReadAll()错误的方法。请参见http://www.dostips.com/forum/viewtopic.php?p=36033#p36033。 - dbenham
11
这真是一颗珍宝。你为什么不将它放在GitHub或作为Gist呢?这样做会使版本控制、后续跟进、发布/分发、修复等更加容易。如果你需要帮助,就告诉我吧。 - Atif Aziz
修复了 JREPL.BAT 的链接。 - dbenham
显示剩余9条评论

44

使用 FNR

使用 fnr 工具。它比 fart 有一些优点:

  • 支持正则表达式
  • 可选 GUI。有一个“生成命令行”按钮,可以创建放置在批处理文件中的命令行文本。
  • 多行模式:GUI 允许您轻松处理多行模式。在 FART 中,您必须手动转义换行符。
  • 允许选择文本文件编码。还有自动检测选项。

在此处下载 FNR:http://findandreplace.io/?z=codeplex

用法示例: fnr --cl --dir "<目录路径>" --fileMask "hibernate.*" --useRegEx --find "查找字符串表达式" --replace "替换字符串"


2
这真不错。能够从图形界面生成命令行是一个很好的简单功能,让我迅速上手。 - David Hammond
1
非常有用的工具。之前尝试过 FART,但是文档已经过时了。 - Artur Kedzior
1
很酷的工具,它甚至支持正则表达式。这是 FART 缺少的东西。 - Dio Phung
2
感谢您指出这个工具。单个exe,是FART的绝佳替代品,因为FART已经不再开发(并且缺少正则表达式);而PowerShell语法实在是太难以忍受了。 - Gras Double
1
替换FART的好工具。然而,不幸的是,http://findandreplace.io/contact-us 告诉我们:Find&Replace的支持目前已暂停。 - Andrey Kazak
显示剩余2条评论

30

我认为没有任何内置命令可以完成这个任务。我建议你下载类似于Gnuwin32UnxUtils的东西,并使用sed命令(或仅下载sed):

sed -c s/FOO/BAR/g filename

3
使用Cygwin(http://www.cygwin.com)。它是最接近实际安装Linux的东西。 - Andrew Johnson
最好能提供一种不依赖于安装Cygwin的解决方案。POSIX字符串操作很简单 - 在Windows上做这个有点更加难以理解。 - Rex
4
Gnuwin32和UnxUtils是专为Windows构建的独立二进制文件,它们不依赖于cygwin。 - Ferruccio
1
cygwin: sed -i -b -e 's/FOO/BAR/g' \find . -name *.txt`` -i -- 直接编辑文件;-b -- 不处理 CR+LF - 如果没有这个选项,CR+LF 将被转换为 LF - Alexey Vishentsev
@AndrewJohnson 观点和信息是两个不同的事情。 - Preza8

28

我知道我有点晚了。。

个人而言,我喜欢这个解决方案: - 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

谢谢!


这基本上是一个文件复制工具,它替换了两个静态字符串 - 你至少可以在那里放置两个变量,这样想要尝试它的人就不需要理解语法才能使用它 -- 另外:对于互联网上的假设几乎总是完全错误的。请记住这一点。 - specializt
好的..那么,你建议我重新编写代码吗?如果是这样,你有什么建议吗?我想现在我所处的位置是它可以工作。我理解你的观点,但是虽然它使用静态变量,但它确实“去重”,从而克服了主要障碍。虽然有一些工具可以满足这个需求,但使用本地CMD可以解决问题。我知道互联网并不总是可信的(因此有关“浴室墙”的评论,人们会写他们想写的任何东西)-您必须进行测试、验证、再验证,并小心发布什么。 - Leptonator
“我们”是谁,以及“静态变量”除了指静态对象变量/成员外,还应该表示什么? - specializt
6
@specializt - 请... 我不是来辩论语义的。如果您愿意,我们可以将这个话题转移到聊天室中讨论。 - Leptonator
5
在我看来,这个就是对原问题的答案。在安装期间,我将使用此技巧配置服务的初始化文件,我不想启用PowerShell,也不想允许脚本引擎在我的服务器上运行。在与Windows相关的问题的解答中,往往以“从那里安装这个小玩意儿”开始,因为仍然存在“个人电脑”的态度。 - mico
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接