Wednesday, November 23, 2011

Search and replace with Windows PowerShell

I was trying to re-brand the source code of our product. It involved replacing the internal code name of the project with the actual product name. 

If you ever had to do some sort  search and replace across a bunch of files with a certain level of control, here is a simple PowerShell script you can use. For example, lets say the task is to replace all instances of "CodeName" with "ProductName" across all files in the current directory. 

Get-Childitem . -rec -name -include *.proj | ForEach-Object { (Get-Content $_) | ForEach-Object {$_ -replace "CodeName", "ProductName" } |Set-Content $_ }

It may seem confusing at once, but there are very consistent simple and easy to follow rules that PoweShell follows. All commands (called cmdlets) in PowerShell are in the form of verb + noun. Just like the first command above Get-ChildItem, there is Get-Process, Get-Content etc The first command 

Get-Childitem . -rec -name -include *.proj 

recursively gets a list of all file names that match *.proj in the directories below the current one.

The output of this command is piped to the next command which is a bit complex

ForEach-Object { (Get-Content $_) | ForEach-Object {$_ -replace "CodeName", "ProductName" } | Set-Content $_ }

The ForEach-Object {...} command simply does 'something' for each object it receives as input from the pipe. The first command sent the list of file names, so its going to do 'something' to this list of names.

This 'something' is another set of commands.

(Get-Content $_) | ForEach-Object {$_ -replace "CodeName", "ProductName" | Set-Content $_ 

Here the $_ represents the current object; a file name with complete path in this case. Get-Content $_ gets the content of the file and pipes the output to another ForEach-Object, which replaces all the instances of string "CodeName" with "ProductName" for each line of the current file's (represented by $_) content.

The replaced file is then written to disk using Set-Content $_ 

Heres another one I wrote to help me automate 'svn move' for files

gci -rec | where { !$_.PsIsContainer } | where { $_.Name.Contains("CodeName") } | foreach { svn move $_.FullName ($_.DirectoryName + "\" + ($_.Name -creplace "CodeName", "ProductName")) }

Here 'gci' and 'foreach' are simply aliases for the more verbose 'Get-ChildItem' and 'ForEach-Object' commands.


Apart from such basic use, PowerShell offers a very impressive set of functions to work with on your machine and well as remote ones, all without having to click-click-click :) Though its mainly oriented towards admin type tasks, I am sure devs can equally exploit its functionality in day to day use.

You can download PowerShell from here

Tip: Quickly delete all unversioned SVN files


I was looking for a quick way to delete all my unversioned SVN files. If you have PowerShell, I came across this very simple command
(svn status --no-ignore) -match '^\?' -replace '^\?\s+' | rm

It finds all matches from the out put of ‘svn status’ command, and then replaces the ‘?’ followed by bunch of white spaces (\s+) to get you the list of files that are unversioned. These files are then removed with the ‘rm’ command.