Filter empty and/or null values with jq

Viewed 24538

I have a file with jsonlines and would like to find empty values.

{"name": "Color TV", "price": "1200", "available": ""}
{"name": "DVD player", "price": "200", "color": null}

And would like to output empty and/or null values and their keys:

available: ""
color: null

I think it should be something like cat myexample | jq '. | select(. == "")', but is not working.

3 Answers

The tricky part here is emitting the keys without quotation marks in a way that the empty string is shown with quotation marks. Here is one solution that works with jq's -r command-line option:

to_entries[]
| select(.value | . == null or . == "")
| if .value == "" then .value |= "\"\(.)\"" else . end
| "\(.key): \(.value)"

Once the given input has been modified in the obvious way to make it valid JSON, the output is exactly as specified.

Some people may find the following jq program more useful for identifying keys with null or empty string values:

with_entries(select(.value |.==null or . == ""))

With the sample input, this program would produce:

{"available":""}
{"color":null}

Adding further information, such as the input line or object number, would also make sense, e.g. perhaps:

with_entries(select(.value |.==null or . == ""))
| select(length>0)
| {n: input_line_number} + .

With a single with_entries(if .value == null or .value == " then empty else . end) filter expression it's possible to filter out null and empty ("") values.

Without filtering:

echo '{"foo": null, "bar": ""}' | jq '.'
{
  "foo": null,
  "bar": ""
}

With filtering:

s3 echo '{"foo": null, "bar": ""}' |  jq 'with_entries(if .value == null or .value == "" then empty else . end)'
{}
Related