File System - Regular Expression Find and Replace (Updated)

Octopus.Script exported 2015-10-26 by bobjwalker belongs to ‘File System’ category.

Find and replace text matching a regular expression in one or more files. Now with working $ replacement.

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Files

RFRCandidatePathGlobs

The files to search. Wildcards * and ** are supported. Paths must be fully-qualified, e.g. C:\MyApp\**\*.xml. Separate multiple paths with ; semicolons.

Pattern

RFRFindRegex

The regular expression to find in the target files.

Substitution

RFRSubstitution

The text to insert in place of each occurrence of Pattern. Regular expression substitutions are supported, so any literal $ in the substitution pattern must be escaped by doubling ($$).

Options

RFROptions = ExplicitCapture

A space-separated list of options from the RegexOptions enumeration.

Script body

Steps based on this template will execute the following PowerShell script.

function Execute-RegexFindReplace($target, $find, $replace, $options) {
    Write-Output "Searching $target..."
    $orig = [System.IO.File]::ReadAllText($target)
    
    $regex = new-object System.Text.RegularExpressions.Regex($find, $options)
    if ([string]::IsNullOrEmpty($replace)) {        
$replace = ''
    }
    
    $occurrences = $regex.Matches($orig).Count
    if ($occurrences -gt 0) {
        Write-Output "Found $occurrences occurrence(s), replacing..."
        
        $replaced = $regex.Replace($orig, $replace)
        [System.IO.File]::WriteAllText($target, $replaced)
    }
}

if ([string]::IsNullOrEmpty($RFRFindRegex)) {
    throw "A non-empty 'Pattern' is required"
}

$options = [System.Text.RegularExpressions.RegexOptions]::None
$RFROptions.Split(' ') | foreach {
    $opt = $_.Trim()
    $flag = [System.Enum]::Parse([System.Text.RegularExpressions.RegexOptions], $opt)
    $options = $options -bor $flag
}

Write-Output "Replacing occurrences of '$RFRFindRegex' with '$RFRSubstitution' applying options $RFROptions"

$RFRCandidatePathGlobs.Split(";") | foreach {
    $glob = $_.Trim()
    Write-Output "Searching for files that match $glob..."

    $matches = $null
    $splits = $glob.Split(@('/**/'), [System.StringSplitOptions]::RemoveEmptyEntries)

    if ($splits.Length -eq 1) {
        $splits = $glob.Split(@('\**\'), [System.StringSplitOptions]::RemoveEmptyEntries)
    }
    
    if ($splits.Length -eq 1) {
        $matches = ls $glob
    } else {
        if ($splits.Length -eq 2) {
            pushd $splits[0]
            $matches = ls $splits[1] -Recurse
            popd
        } else {
            $splits
            throw "The segment '**' can only appear once, as a directory name, in the glob expression"

        }
    }

    $matches | foreach {
        
        $target = $_.FullName

        Execute-RegexFindReplace -target $target -find $RFRFindRegex -replace $RFRSubstitution -options $options
    }
}


Write-Output "Done."

Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "0bef8c07-5739-4030-8c04-287ceeb51153",
  "Name": "File System - Regular Expression Find and Replace (Updated)",
  "Description": "Find and replace text matching a regular expression in one or more files. Now with working $ replacement.",
  "Version": 7,
  "ExportedAt": "2015-10-26T21:24:18.756+00:00",
  "ActionType": "Octopus.Script",
  "Author": "bobjwalker",
  "Parameters": [
    {
      "Name": "RFRCandidatePathGlobs",
      "Label": "Files",
      "HelpText": "The files to search. Wildcards `*` and `**` are supported. Paths must be fully-qualified, e.g. `C:\\MyApp\\**\\*.xml`. Separate multiple paths with `;` semicolons.",
      "DefaultValue": null,
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Name": "RFRFindRegex",
      "Label": "Pattern",
      "HelpText": "The regular expression to find in the target files.",
      "DefaultValue": null,
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Name": "RFRSubstitution",
      "Label": "Substitution",
      "HelpText": "The text to insert in place of each occurrence of _Pattern_. Regular expression [substitutions](http://msdn.microsoft.com/en-us/library/ewy2t5e0.aspx) are supported, so any literal `$` in the substitution pattern must be escaped by doubling (`$$`).",
      "DefaultValue": null,
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Name": "RFROptions",
      "Label": "Options",
      "HelpText": "A space-separated list of options from the [RegexOptions](http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regexoptions.aspx) enumeration.",
      "DefaultValue": "ExplicitCapture",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptBody": "function Execute-RegexFindReplace($target, $find, $replace, $options) {\n    Write-Output \"Searching $target...\"\n    $orig = [System.IO.File]::ReadAllText($target)\n    \n    $regex = new-object System.Text.RegularExpressions.Regex($find, $options)\n    if ([string]::IsNullOrEmpty($replace)) {        \n$replace = ''\n    }\n    \n    $occurrences = $regex.Matches($orig).Count\n    if ($occurrences -gt 0) {\n        Write-Output \"Found $occurrences occurrence(s), replacing...\"\n        \n        $replaced = $regex.Replace($orig, $replace)\n        [System.IO.File]::WriteAllText($target, $replaced)\n    }\n}\n\nif ([string]::IsNullOrEmpty($RFRFindRegex)) {\n    throw \"A non-empty 'Pattern' is required\"\n}\n\n$options = [System.Text.RegularExpressions.RegexOptions]::None\n$RFROptions.Split(' ') | foreach {\n    $opt = $_.Trim()\n    $flag = [System.Enum]::Parse([System.Text.RegularExpressions.RegexOptions], $opt)\n    $options = $options -bor $flag\n}\n\nWrite-Output \"Replacing occurrences of '$RFRFindRegex' with '$RFRSubstitution' applying options $RFROptions\"\n\n$RFRCandidatePathGlobs.Split(\";\") | foreach {\n    $glob = $_.Trim()\n    Write-Output \"Searching for files that match $glob...\"\n\n    $matches = $null\n    $splits = $glob.Split(@('/**/'), [System.StringSplitOptions]::RemoveEmptyEntries)\n\n    if ($splits.Length -eq 1) {\n        $splits = $glob.Split(@('\\**\\'), [System.StringSplitOptions]::RemoveEmptyEntries)\n    }\n    \n    if ($splits.Length -eq 1) {\n        $matches = ls $glob\n    } else {\n        if ($splits.Length -eq 2) {\n            pushd $splits[0]\n            $matches = ls $splits[1] -Recurse\n            popd\n        } else {\n            $splits\n            throw \"The segment '**' can only appear once, as a directory name, in the glob expression\"\n\n        }\n    }\n\n    $matches | foreach {\n        \n        $target = $_.FullName\n\n        Execute-RegexFindReplace -target $target -find $RFRFindRegex -replace $RFRSubstitution -options $options\n    }\n}\n\n\nWrite-Output \"Done.\"",
    "Octopus.Action.Script.Syntax": "PowerShell"
  },
  "Category": "File System",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/file-system-regular-expression-find-and-replace.json",
  "Website": "/step-templates/0bef8c07-5739-4030-8c04-287ceeb51153",
  "Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKhQTFRF/////78A/6oAVVVV/++//+q/gICA1dXV/79A/9R///ff/8MQ/9dg/8cg//vv/68A/+ef//PP//rv/7Ug/68Q/+Sv/8sw/9tw/9NQ/89w/+uv/+OP/8pg/89A/8VQ/9+f/9+A/9qP/+/P/99//7cA/7IA/7wA/6sA/+/A39/f/64A2tjX//Tfn5+f/7MA/7sA/74A/60A/9Zw/7gA/74Q/7oA/7UA/7EAi6g4fwAAAuRJREFUeNrs21tT2mAUheEvaaCQQCSczyi29WzP7f//Z6UdZBIIM44us9hf13vbC+eRbLo3qnNKKaWUUkoppZRSSimllFJKKaWUwlVrLhsvbrLqnoai2+yFr2x+fwKOwasZm/oXdEczxDQnOyYhqgn3uQpxDZhz3gdCesQ3r3mIjDfwXagj7NEgKywkXLMgSzCE9mz1wBDaOzDYETYEEUSQ/wPSaz6rQa174pDnt1x5Atm8emtPIGG48gUClJAh/XtPILi36+L3Zz6oVdBF4w32/sIbYmWH6qAPX5fzjio/14Q/W7nnqtIPDnYfFfThkGpPovXu68IhNdKSVyXkoQ7qgQypvwNVFwQDuXkP6oYM8WbYBWFDYMPNHnZBTv3tV8MuiCC+Q6K36+ypkn/LsJC4lQSkhhkQch4Qa+MgrYBahIKcB35AYrIjyEAQ9gsCm5E2GTIDQabsJysFQcZkxxj0H2LKfkGmIMjM3KgfgbBHfQSCROwnKwZByNtJsACt8WlChnRAkA7ZkaAOqyEZ0gJB7O2LRyAjsmOIutlNjnoJhD3qL9gXyyFjk6N+CKGPegSC2DsNj0DY++IlCEI/DWMQhL0vjh0GYvE0LIWwT8PEgSDsfXEEgmRmR30PYvI0LIGkRvfFAwj9NExBkIXRfXEfYvQ0PISwT8O2A0HYoz4DQb4ZPQ0PID8sj3oO8tXuvliEPJoe9Rzkk9XTcA9yZnhfLEA+mD0Ni5Ar9gvSAUE+2j0Ni5DPdk/DAuTW9L6Yg7BHfehAkC/WR30LoY96CoL8tL0v7iD0fTECQX4Z3xd3EPa+OANBflvfF58g363vi1sIfV+cgiCPPoz6Xwh71EcgyK0Xo76BsPfFBcbhrjzYF/9l/zTcxj4NWyBH7Mmo038zFvWCsCHt1HnxaCWZg8X8ifQwxjlcSvsJaHLpsGW5v2S8vo4qyymF7+5O3wOllFJKKaWUUkoppZRSSimllPKxPwIMAPj2YtijZbi5AAAAAElFTkSuQmCC",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Monday, October 26, 2015