Welcome!

A Software Architect Living in a Networking World

Joe Pruitt

Subscribe to Joe Pruitt: eMailAlertsEmail Alerts
Get Joe Pruitt via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Blog Feed Post

Unix To PowerShell - Basename

PowerShell_unix PowerShell is definitely gaining momentum in the windows scripting world but I still hear folks wanting to rely on Unix based tools to get their job done.  In this series of posts I’m going to look at converting some of the more popular Unix based tools to PowerShell.

basename

The Unix “basename” command will delete any prefix up to the last slash (‘/’) character and return the result. 

For my PowerShell implementation, I’ve switched the slash path separator character with the Windows backslash (‘\’) path separator. 

PowerShell does have the Split-Path cmdlet that will parse a path into it’s components.  And with it’s “-Leaf” argument, you can extract the basename equivalent.  My first implementation used this route, but the Split-Path cmdlet didn’t work correctly with relative paths.  More specifically, the Unix command passing in “.” would return “.”.  PowerShell returns the value of the current directory.   I tested out the “-LiteralPath” option but it still required a “-Path” option and would not interpret the “.” or “..” as literal strings.

So, I went ahead and wrote a little reverse string walking loop which turns out to be about 25% faster than using “Split-Path –Leaf”.  I’ve also included in this script a few unit tests I ran to verify the output.

 

   1: #----------------------------------------------------------------
   2: # Dirname.ps1
   3: #----------------------------------------------------------------
   4: param
   5: (
   6:   [string]$name = $null
   7: );
   8:  
   9: $script:SEPARATOR = "\";
  10:  
  11: #----------------------------------------------------------------
  12: # function Do-Basename
  13: #----------------------------------------------------------------
  14: function Do-Basename()
  15: {
  16:   param
  17:   (
  18:     [string]$name = $null
  19:   );
  20:   
  21:   $basename = "";
  22:   
  23:   if ( $name  )
  24:   {
  25:     if ( $name.EndsWith($script:SEPARATOR) )
  26:     {
  27:       $name = $name.SubString(0, $name.Length -1);
  28:     }
  29:     $i = 0;
  30:     for ($i = $name.Length-1; $i -ge 0; $i--)
  31:     {
  32:       if ( $name[$i] -eq $script:SEPARATOR )
  33:       {
  34:         break;
  35:       }
  36:     }
  37:     if ( $i -ge 0 )
  38:     {
  39:       $basename = $name.SubString($i+1)
  40:     }
  41:     else
  42:     {
  43:       $basename = $name;
  44:     }
  45:   }
  46:   $basename;
  47: }
  48:  
  49: #----------------------------------------------------------------
  50: # function Do-BasenameUnitTests
  51: #----------------------------------------------------------------
  52: function Do-BasenameUnitTests()
  53: {
  54:   $tests = @( 
  55:     @("foo", "foo"),
  56:     @("foo\", "foo"),
  57:     @("", ""),
  58:     @("\foo", "foo"),
  59:     @("\foo\", "foo"),
  60:     @("\foo\bar", "bar"),
  61:     @("\foo\bar\", "bar"),
  62:     @("c:\foo", "foo"),
  63:     @("c:\foo\bar", "bar"),
  64:     @("c:\foo\bar\", "bar"),
  65:     @("c:\foo\bar\ ", " "),
  66:     @(".", "."),
  67:     @("..", ".."),
  68:     @(".\", "."),
  69:     @("..\", ".."),
  70:     @("..\.", "."),
  71:     @("..\.\foo", "foo")
  72:   );
  73:   
  74:   $success = "PASS";
  75:   
  76:   "  {0,-15}      {1,-15}       {2,-15}    {3}" -f ("Test", "Expected", "Found", "Pass");
  77:   foreach ($test in $tests)
  78:   {
  79:     $result = Do-Basename $test[0];
  80:     $status = $result -eq $test[1];
  81:     "({0,-15} -> {1,-15}) -> {2,-15} : {3}" -f ("""$($test[0])""", """$($test[1])""", """$($result)""", $status);
  82:     #Write-Host "TEST: (""$($test[0])"" -> ""$($test[1])"") -> ""$result"" : $status";
  83:     if ( ! $status ) { $success = "FAIL"; }
  84:   }
  85:   ""
  86:   "RESULT: $success";
  87: }
  88:  
  89: Do-Basename -name $name;
  90: #Do-BasenameUnitTests;

You can download the full script here: Basename.ps1

Read the original blog entry...

More Stories By Joe Pruitt

Joe Pruitt is a Principal Strategic Architect at F5 Networks working with Network and Software Architects to allow them to build network intelligence into their applications.