I need to find those ethernet interfaces, which are up.
I tried this:
$ ip -d -j a s | jq 'map(select ((.link_type == "ether") and (.flags[] | contains
("UP")))) | map(.ifname)'
But it returns two results,
[
"enp0s3",
"enp0s3"
]
although ip lists this interface only once.
$ ip -d -j a s | jq 'map(.ifname)'
[
"lo",
"enp0s3",
"enp0s8"
]
It seems to me that the and in the select behaves like an or. It returns those interfaces, which have .link_type = "ether" or .flags[] | contains ("UP").
But when I try the same with a more basic example,
$ jq 'map(select((. > 1) and (. < 3)))' <<<'[1, 2, 3]'
it works as expected:
[
2
]
What did I wrong?
>Solution :
This is one of common pitfalls associated with using select(..). You are actually expanding the data twice, once w.r.t. to the root level and once again with .flags[] leading to combinatorial explosion
The solution would be to move .flags[] outside select as below
map(.flags[] as $x | select ((.link_type == "ether") and ( $x | contains ("UP"))))
Also it seems the flags can take the values UP and LOWER_UP, if you were looking for an exact match, use an equality operator == or a strict regex match, e.g. with test(..)
A simple lookup for just UP in case if you are not running into the above explosion would be to just do
map(select( (.link_type == "ether") and (.flags[] == "UP") ))