---
title: Filtering and transforming output
description: "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."
component: pingcli
version: 1.0
page_id: pingcli:using_pingcli:filtering-output
canonical_url: https://developer.pingidentity.com/pingcli/1.0/using_pingcli/filtering-output.html
revdate: June 8, 2026
section_ids:
  query-and-jmespath: "--query and JMESPath"
  extracting-a-single-field: Extracting a single field
  projecting-multiple-fields: Projecting multiple fields
  accessing-nested-fields: Accessing nested fields
  jmespath-and-string-comparisons: JMESPath and string comparisons
  when-jmespath-is-not-enough: When JMESPath is not enough
  jq: jq
  filtering-with-select: Filtering with select()
  compound-filters: Compound filters
  reshaping-records: Reshaping records
  counting-results: Counting results
  tab-separated-output-for-shell-scripts: Tab-separated output for shell scripts
  filtering-ndjson: Filtering ndjson
  choosing-between-query-and-jq: Choosing between --query and jq
  learn-more: Learn more
---

# 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](../output_schema_reference/output-schema-reference.html) for the complete envelope structure. |

## --query and JMESPath

The `--query` flag evaluates a [JMESPath](https://jmespath.org/) 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:

```bash
pingcli pingone environments list -O json --query 'data[].name'
```

```json
[
  "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:

```bash
pingcli pingone environments list -O json --query 'data[].{id: id, name: name, type: type}'
```

```json
[
  {
    "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`):

```bash
pingcli pingone environments list -O json --query 'data[].{name: name, license: license.id}'
```

```json
[
  {
    "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:

```bash
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](https://jqlang.org/download/).

### Filtering with select()

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

```bash
pingcli pingone environments list -O json | jq '.data[] | select(.type == "PRODUCTION") | .name'
```

```text
"Helpdesk Training"
"Terraform Data Protection Test Environment"
"DaVinci Administrators"
"Administrators"
```

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

```bash
pingcli pingone environments list -O json | jq -r '.data[] | select(.type == "PRODUCTION") | .name'
```

```text
Helpdesk Training
Terraform Data Protection Test Environment
DaVinci Administrators
Administrators
```

### Compound filters

Combine conditions with `and` and `or`:

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

```text
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:

```bash
pingcli pingone environments list -O json | \
  jq '[.data[] | select(.type == "PRODUCTION") | {id, name}]'
```

```json
[
  {
    "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

```bash
# Count all environments
pingcli pingone environments list -O json | jq '.data | length'
```

```text
29
```

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

```text
6
```

### Tab-separated output for shell scripts

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

```bash
pingcli pingone environments list -O json | \
  jq -r '.data[] | select(.type == "PRODUCTION") | "\(.name)\t\(.id)"'
```

```text
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:

```bash
# 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):

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

```text
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:

```bash
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` |

## Learn more

* [pingcli pingone environments list](../command_reference/pingcli_pingone_environments_list.html)

* [Output formats](output-formats.html)

* [JSON output schema reference](../output_schema_reference/output-schema-reference.html)

* [Return codes](return-codes.html)
