I am iterating over kubectl
output that looks similar to this:
{
"apiVersion": "v1",
"items": [
{
"kind": "Pod",
"metadata": {
"name": "ubuntu1",
"namespace": "development-namespace1",
},
],
{
"kind": "Pod",
"metadata": {
"name": "ubuntu2",
"namespace": "development-namespace2",
},
],
}
I am trying to learn jq
, but my command to get a value out of the first dictionary is really long:
kubectl get pods -o json -A | jq '.items | .[] | select(.metadata.name == "ubuntu1") | .metadata.namespace'
How can I shorten this?
jq
version: 1.6
1.28.3
Using this (abbreviated) json output dumped from kubectl get pods -o json -A
...
{
"apiVersion": "v1",
"items": [
{
"kind": "Pod",
"metadata": {
"name": "ubuntu1",
"namespace": "development-namespace1",
},
],
{
"kind": "Pod",
"metadata": {
"name": "ubuntu2",
"namespace": "development-namespace2",
},
],
}
As @pmf said in a comment, you can select the value of a key nested in that array using this:
jq '.items[] | select(.metadata.name == "ubuntu1").metadata.namespace'
.items[]
returns the array keyed by items
select(.metadata.name == "ubuntu1")
:
metadata.name
and value: ubuntu1
select(.metadata.name == "ubuntu1").metadata.namespace
returns value of the .metadata.namespace
in the selected dictionaryTo reiterate, jq '.items[] | select(.metadata.name == "ubuntu1")
returns:
{
"metadata": {
"name": "ubuntu1",
"namespace": "development-namespace1",
}
}
Assume you want to parse the output of the ps command...
Assume ps | <insert-sed-jq-pipe-here>
returns the following...
$ ps | <insert-sed-jq-pipe-here>
PID TTY TIME CMD
11899 pts/0 00:00:18 bash
2694259 pts/0 00:00:00 ps
2694260 pts/0 00:00:00 sed
2694261 pts/0 00:00:00 jq
$
You can convert any columnized text to json with:
jq -sR '[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]]'
This example will dump the aforementioned ps
as json...
$ ps | sed -ne '/PID/,$ p' | jq -sR '[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]]'
[
[
"PID",
"TTY",
"TIME",
"CMD"
],
[
"11899",
"pts/0",
"00:00:18",
"bash"
],
[
"2694259",
"pts/0",
"00:00:00",
"ps"
],
[
"2694260",
"pts/0",
"00:00:00",
"sed"
],
[
"2694261",
"pts/0",
"00:00:00",
"jq"
]
]
$
You can even use this technique on top
... but top
looks a little tricky at first because:
PID
column header.... example:$ top -bn 1 | head -n 8
top - 08:54:54 up 14 days, 1:13, 0 user, load average: 0.11, 0.22, 0.30
Tasks: 96 total, 1 running, 95 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 6.7 sy, 0.0 ni, 93.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 3767.1 total, 109.5 free, 2140.8 used, 1990.5 buff/cache
MiB Swap: 1024.0 total, 898.2 free, 125.8 used. 1626.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2371290 root 20 0 1931856 48168 27024 S 6.7 1.2 0:30.64 flanneld
$
You can solve the interactive top
problem with top -bn 1
, which will run top once in non-interactive mode.
Finally, that same sed
we used in the ps
command will strip off the lines before the top
PID
... so the final top
command as json is:
$ top -bn 1 | sed -ne '/PID/,$ p' | jq -sR '[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]]'
... insert-top-json-output-here
$