pvy4917
pvy4917

Reputation: 1832

How do I extract fields from the tabular text output of the Cloud Foundry CLI?

I have a Cloud Foundry CLI command, cf apps, that outputs:

name       requested state   processes   routes
appname_1   started           web:2/2    route1.com
appname_2   started           web:1/1    route2.com

How do I access all name column values, and then loop over them?

The idea is to get the list of all app names and run the cf delete <app_name> so that I can avoid the hassle of having to delete the apps one by one.

I tried the following script earlier

Fetch apps

$apps = cf apps | Where-Object { 
    $_ -match 'appname'
} | % { $_.Trim() } | ConvertFrom-String -PropertyNames 'Name','Value'

And then use for-loop to delete the apps using cf delete <appname> -f command

for ($i = 0; $i -lt $apps.Length; $i++) {
    $char = $apps.Name[$i]
    cf delete $char -f
}

Upvotes: 0

Views: 115

Answers (1)

mklement0
mklement0

Reputation: 439777

Preface:

  • The solution below uses text parsing to convert the tabular text output to objects, reflecting all the fields in the table, not just name.

    • A simpler solution that extracts the name fields only is:

      $names =  
        cf apps |
        select -Skip 1 | 
        foreach { ($_ -split '  ', 2)[0] }
      
  • Such an approach is best avoided, but cannot always be, namely if the source CLI lacks support for outputting a structured text format, such as JSON or CSV; indeed that seems to be the case for the CloudFoundry cf, as of this writing.


Use the following, which makes the following assumptions, which are consistent with your sample data:

  • Column-header as well as data-row fields must be separated by two or more spaces.
# Initialize helper variables.
$propNames = $null
$ohtTemplate = [ordered] @{}

# Parse the tabular CLI output into objects.
$appInfos = 
  cf apps | 
    ForEach-Object {
      $fields = ($_ -split ' {2,}').Trim()
      if ($null -eq $propNames) { 
        $propNames = $fields
        foreach ($propName in $propNames) {
          $ohtTemplate[$propName] = $null
        }
        return 
      }
      foreach ($i in 0..($propNames.Count-1)) {
        if ($i -lt $fields.Count) {
          $ohtTemplate[$propNames[$i]] = $fields[$i]
        }
        else {
          $ohtTemplate[$propNames[$i]] = $null
        }
      }
      [pscustomobject] $ohtTemplate
    }

# Output the resulting objects, for visual inspection.
$appInfos

The above emits custom objects whose property names correspond to the table header, and whose values contain a row's column values (which are all stored as strings).

PowerShell's for-display output-formatting system conveniently renders the resulting objects as follows:

name         requested state   processes     routes
----         ---------------   ---------     ------
appname_1    started           web:2/2       route1.com
appname_2    started           web:1/1       route2.com

To get just the names, for instance, as an array, using member-access enumeration, use $appInfos.name:

# Output from `$appInfos.name`
appname_1
appname_2

To get just the first app's name, use $appInfos[0].name.

Of course, you can use $appInfos | ForEach-Object { <# work with $_ #> }, foreach ($app in $appInfos) { <# work with $app #> } or $appInfos.ForEach({ <# work with $_ #> }), as usual, to iterate over all app infos.

Upvotes: 1

Related Questions