Configuration Automation - Ping CLI

Filtering and transforming output

Ping CLI gives you two ways to filter and reshape command output: the built-in --query flag for JMESPath expressions, and standard Unix pipes to jq for more expressive transformations. This page covers both tools in depth: when to reach for each, and how to combine them.

Both --query and jq require json or ndjson output. If you are using the default text format, switch to json first: add -O json to your command.

--query applies its expression to the full JSON output envelope. Command results are under the data key: use data[] for array results and data for single-object results. Refer to JSON output schema reference for the complete envelope structure.

--query and JMESPath

The --query flag evaluates a JMESPath expression against the JSON response before printing it. Because the expression runs inside Ping CLI, you don’t need to install any additional tools; it works wherever Ping CLI runs.

JMESPath is well-suited for:

  • Extracting a single field or a list of fields from every record.

  • Projecting a subset of fields to reduce noise.

  • Simple equality filters on known values.

Extracting a single field

To get just the name of every environment, project the field across the data array:

pingcli pingone environments list -O json --query 'data[].name'
[
  "Policy Change Feature Development",
  "Integration Testing",
  "Helpdesk Training",
  "Sandbox Testing",
  "Administrators"
]

Projecting multiple fields

Use a multi-value projection to select a named subset of fields from each record:

pingcli pingone environments list -O json --query 'data[].{id: id, name: name, type: type}'
[
  {
    "id": "03414408-42f9-4011-b45c-b46c7cc8028b",
    "name": "Policy Change Feature Development",
    "type": "SANDBOX"
  },
  {
    "id": "5e35b284-e3e4-4b5d-b378-d70674940ac3",
    "name": "Helpdesk Training",
    "type": "PRODUCTION"
  }
]

The keys on the left of : become the output field names, so you can rename fields in the same step.

Accessing nested fields

Use dot notation to reach into nested objects. For example, to extract the license ID (nested under license.id):

pingcli pingone environments list -O json --query 'data[].{name: name, license: license.id}'
[
  {
    "name": "Policy Change Feature Development",
    "license": "3eb902be-3d37-4926-9c8f-150716e955d3"
  },
  {
    "name": "Helpdesk Training",
    "license": "54776175-9a9f-4c21-a4c7-ecb975aa9b56"
  }
]

JMESPath and string comparisons

String literals in JMESPath filter expressions must be wrapped in backticks and double-quoted:

pingcli pingone environments list -O json --query 'data[?type==`"PRODUCTION"`].name'

The unusual quoting (a backtick-wrapped, double-quoted string) is a requirement of the JMESPath specification, not a shell quirk. When a filter comparison against a string value returns no results, check that you have both the outer backticks and the inner double quotes.

When JMESPath is not enough

JMESPath does not support:

  • Substring matching or regular expressions.

  • Sorting or ordering results.

  • Counting or aggregating values.

  • Reshaping data (for example, flattening nested arrays, computing derived fields).

For these tasks, reach for jq.

jq

jq is a standalone JSON processor you pipe output into. It is more expressive than JMESPath and is the right choice when you need substring matching, sorting, counting, or any transformation that JMESPath cannot express.

If jq is not installed, see the jq download page.

Filtering with select()

Use select() to keep only records that match a condition. For example, to list only PRODUCTION environments:

pingcli pingone environments list -O json | jq '.data[] | select(.type == "PRODUCTION") | .name'
"Helpdesk Training"
"Terraform Data Protection Test Environment"
"DaVinci Administrators"
"Administrators"

Add the -r flag to strip the surrounding quotes from string output:

pingcli pingone environments list -O json | jq -r '.data[] | select(.type == "PRODUCTION") | .name'
Helpdesk Training
Terraform Data Protection Test Environment
DaVinci Administrators
Administrators

Compound filters

Combine conditions with and and or:

# Sandbox environments whose name contains "Terraform"
pingcli pingone environments list -O json | \
  jq -r '.data[] | select(.type == "SANDBOX" and (.name | test("Terraform"))) | .name'
Terraform Test
Terraform Demo

test("pattern") applies a regular expression: use this wherever JMESPath would fall short.

Reshaping records

Build a new object from selected fields using {key: expression} syntax:

pingcli pingone environments list -O json | \
  jq '[.data[] | select(.type == "PRODUCTION") | {id, name}]'
[
  {
    "id": "5e35b284-e3e4-4b5d-b378-d70674940ac3",
    "name": "Helpdesk Training"
  },
  {
    "id": "e7e7e106-9547-438c-a30b-0882cb267c10",
    "name": "DaVinci Administrators"
  },
  {
    "id": "4c33a4c6-7489-43fe-aa3c-87bd55520427",
    "name": "Administrators"
  }
]

Wrapping the expression in […​] collects results into an array instead of printing them as separate lines.

Counting results

# Count all environments
pingcli pingone environments list -O json | jq '.data | length'
29
# Count production environments only
pingcli pingone environments list -O json | \
  jq '[.data[] | select(.type == "PRODUCTION")] | length'
6

Tab-separated output for shell scripts

Use string interpolation to produce tab-separated values you can feed to other shell commands:

pingcli pingone environments list -O json | \
  jq -r '.data[] | select(.type == "PRODUCTION") | "\(.name)\t\(.id)"'
Helpdesk Training	5e35b284-e3e4-4b5d-b378-d70674940ac3
Terraform Data Protection Test Environment	0c442e65-9bab-4017-8d44-71fe0c9be286
DaVinci Administrators	e7e7e106-9547-438c-a30b-0882cb267c10
Administrators	4c33a4c6-7489-43fe-aa3c-87bd55520427

Filtering ndjson

Both --query and jq work with ndjson, but the expression targets a single record rather than an array.

With bare -O ndjson, each line is a raw record with no envelope wrapper. Reference fields directly: do not use data. prefix:

# Print only the name field from every record
pingcli pingone environments list -O ndjson --query 'name'

With jq, use select() directly on the stream (jq processes each line independently):

pingcli pingone environments list -O ndjson | \
  jq -r 'select(.type == "PRODUCTION") | .name'
Helpdesk Training
Terraform Data Protection Test Environment
DaVinci Administrators
Administrators

If you need envelope fields (such as status or meta) alongside each record, use -O ndjson-wrapped instead. With ndjson-wrapped, records are wrapped in the full envelope and field access uses .data.name, .data.type, and so on:

pingcli pingone environments list -O ndjson-wrapped | \
  jq -r 'select(.data.type == "PRODUCTION") | .data.name'

Choosing between --query and jq

Need

Use

Why

Extract or project fields

--query

Zero dependencies; shorter command line

Equality filter on a known value

--query

Straightforward; works without installing jq

Substring or regex match

jq

JMESPath has no contains() for strings or regex support

Sort, count, or aggregate

jq

JMESPath does not support these operations

Compute derived fields or reshape output significantly

jq

jq can construct arbitrary new JSON structures

Process one record at a time in a shell loop

ndjson + jq

No need to parse a full JSON document; loop with while read