how to replace string in file using msbuild?

后端 未结 8 2052
庸人自扰
庸人自扰 2020-12-01 09:05

I want to replace a string such \"how r u\" in file test.xml with a string \"i am fine\" in another file xy.xml.using regular expression in ms build.

ie i have to r

相关标签:
8条回答
  • 2020-12-01 09:34

    You can use the task FileUpdate from MSBuild Community Tasks as explained in the article http://geekswithblogs.net/mnf/archive/2009/07/03/msbuild-task-to-replace-content-in-text-files.aspx

    0 讨论(0)
  • 2020-12-01 09:35

    The answer from @csharptest.net is good, but it doesn't work on DotNetCore. I would have added this as a comment, but I don't have enough reputation.

    On DotNetCore you have to update:

    • Task Factory to "RoslynCodeTaskFactory"
    • Task Assembly to "$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"
    • Remove the reference to "System.Core"
    • The consuming Target has to specify the "AfterTargets" attribute as "Build"

    Everything else should be the same:

    <Project Sdk="Microsoft.NET.Sdk.Web">
      ...
    
      <UsingTask
        TaskName="ReplaceFileText"
        TaskFactory="RoslynCodeTaskFactory"
        AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
          <InputFilename ParameterType="System.String" Required="true" />
          <OutputFilename ParameterType="System.String" Required="true" />
          <MatchExpression ParameterType="System.String" Required="true" />
          <ReplacementText ParameterType="System.String" Required="true" />
        </ParameterGroup>
        <Task>
          <Using Namespace="System"/>
          <Using Namespace="System.IO"/>
          <Using Namespace="System.Text.RegularExpressions" />
          <Code Type="Fragment" Language="cs">
            <![CDATA[  
              File.WriteAllText(
                OutputFilename,
                Regex.Replace(File.ReadAllText(InputFilename), MatchExpression, ReplacementText)
                );
            ]]>
          </Code>
        </Task>
      </UsingTask>
    
      <Target Name="AfterBuildStep" AfterTargets="Build">
        <ReplaceFileText
           InputFilename="$(OutputPath)File.exe.config" 
           OutputFilename="$(OutputPath)File.exe.config" 
           MatchExpression="\$version\$" 
           ReplacementText="1.0.0.2" />
      </Target>
    </Project>
    
    0 讨论(0)
  • 2020-12-01 09:36

    If you prefer not using third party (community) binaries, nor embedding code into your msbuild project, I'd suggest creating a simple task library which implements File.WriteAllText and can later host other tasks :

    using System.IO;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    
    public class FileWriteAllText : Task
    {
        [Required]
        public string Path { get; set; }
        [Required]
        public string Contents { get; set; }
    
        public override bool Execute()
        {
            File.WriteAllText(Path, Contents);
            return true;
        }
    }
    

    Then you can replace, append, etc. in msbuild :

    <UsingTask TaskName="FileWriteAllText" AssemblyFile="MyTasks.dll" />
    <FileWriteAllText Path="test.xml"
         Contents="$([System.Text.RegularExpressions.Regex]::Replace(
             $([System.IO.File]::ReadAllText('test.xml')), 'how r u', 'i am fine'))" />
    
    0 讨论(0)
  • 2020-12-01 09:39

    I ran the both replacements against same file that sits on a Unix drive and used the unc path to it \server\path...:

    <ReplaceFileText
      InputFilename="$(fileToUpdate)"
      OutputFilename="$(fileToUpdate)"
      MatchExpression="15.0.0"
      ReplacementText="15.3.1"/>
    
    
    <FileUpdate Files="$(fileToUpdate2)"
                Regex="15.0.0"
                ReplacementText="15.3.1" />
    

    and the cs custom action above does not add the bom; however the FileUpdate did:

    %head -2 branding.h branding2.h
    ==> branding.h <==
    #/* branding.h
    #** This file captures common branding strings in a format usable by both sed and C-preprocessor.
    
    ==> branding2.h <==
    #/* branding.h
    #** This file captures common branding strings in a format usable by both sed and C-preprocessor.
    

    Thanks csharptest.net - I was doing doing exec's with perl subtitute commands for unix builds.

    0 讨论(0)
  • 2020-12-01 09:44

    An updated to answer from James

      <UsingTask TaskName="ReplaceTextInFiles" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.$(VsBuildTaskBinarySuffix).dll">
    <ParameterGroup>
      <MatchExpression ParameterType="System.String" Required="true" />
      <ReplacementExpression ParameterType="System.String" Required="true" />
      <InputFile ParameterType="Microsoft.Build.Framework.ITaskItem" Required="true" />      
      <IsTextReplaced ParameterType="System.Boolean"  Output="True"/>
    </ParameterGroup>
    <Task>
      <Reference Include="System.Core" />
      <Using Namespace="System" />
      <Using Namespace="System.IO" />
      <Using Namespace="System.Text.RegularExpressions" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
          bool isMatchFound = false;
          string filecontent = "";
          string path = InputFile.ItemSpec;
    
          Log.LogMessage(MessageImportance.High, "[ReplaceTextInFiles]: Match= " + MatchExpression);
          Log.LogMessage(MessageImportance.High, "[ReplaceTextInFiles]: Replace= " + ReplacementExpression);
    
          IsTextReplaced = false;
          using(StreamReader rdr = new StreamReader(path))
          {
            filecontent = rdr.ReadToEnd();
            if (Regex.Match(filecontent, MatchExpression).Success)
            {
              filecontent = Regex.Replace(filecontent, MatchExpression, ReplacementExpression);
              isMatchFound = true;            
            }
          }
    
          if(isMatchFound){
            using(StreamWriter wrtr = new StreamWriter(path))
            {
              wrtr.Write(filecontent);
              IsTextReplaced = true;
              Log.LogMessage(MessageImportance.Normal, "[ReplaceTextInFiles]: Replaced text in file:" + path);
            }
          }       
        ]]>
      </Code>
    </Task>
    

    0 讨论(0)
  • 2020-12-01 09:46

    EDIT: This answer is obsolete. Use solution below...

    Use ReadLinesFromFile task to get replacement string from the xy.xml file. Check this

    Then use value from xy.xml as a replacement string for FileUpdate task. Check this

    And put it all together ;)

    0 讨论(0)
提交回复
热议问题