使用通配符从 jq 打印(或合并到第一个非空值)

Print from jq using a wild card (or coalesce to first non null)

我有以下命令:

kubectl get pod -A -o=json | jq -r '.items[]|select(any( .status.containerStatuses[]; .state.waiting or .state.terminated))|[.metadata.namespace, .metadata.name]|@csv'

这个命令效果很好。它输出我失败的命名空间和名称 pods.

但现在我想在结果中再添加一列。我想要的列位于两个位置之一(并且只有一个):

我首先尝试将 .status.containerStatuses[].state.*.reason 添加到结果字段数组。但这给了我一个 unexpected '*' 编译错误。

然后我开始考虑如何使用 SQL 或其他编程语言来做到这一点。他们经常有一个函数将 return 其参数的第一个非空值。 (这通常称为合并)。但是我找不到 jq.

的任何此类命令

我怎样才能 return reason 作为我查询的结果?

jq 以 // 的形式对应于“合并”。 例如,null // 0 的计算结果为 0,很可能在您的情况下就足够了,也许:

.status.containerStatuses[].state | (.waiting // .terminated) | .reason

.status.containerStatuses[].state | (.waiting.reason // .terminated.reason )

或类似。

但是,// 只能在对它的作用有所了解的情况下使用,如 https://github.com/stedolan/jq/wiki/FAQ#or-versus-

的 jq FAQ 中的详细解释

如果 // 由于某种原因不适用,那么明显的替代方法是 if ... then ... else ... end 语句,这与 C 的 _ ? _ : _ 非常相似,因为它可用于生成值,例如类似于:

.status.containerStatuses[].state
| if has("waiting") then .waiting.reason
  else .terminated.reason
  end

但是,如果 containerStatuses 是数组,则可能需要注意一些。

如果您想使用 coalesce:

# Stream-oriented version
def coalesce(s):
  first(s | select(. != null)) // null;

或者如果您更喜欢使用数组:

# Input: an array
# Output: the first non-null element if any, else null
def coalesce: coalesce(.[]);

使用面向流的版本,您可以使用通配符按照您的想法编写一些内容,例如

coalesce(.status.containerStatuses[].state[].reason?)