JQ:枚举对象流

JQ: Enumerate Object Stream

我有一个装满对象的管道,我正在尝试使用 jq 向流中的每个对象添加一个累积计数字符串以获得以下输出

{"count":"Num_000"}
{"count":"Num_001"}
{"count":"Num_002"}
{"count":"Num_003"}
{"count":"Num_004"}
{"count":"Num_005"}
{"count":"Num_006"}
{"count":"Num_007"}
{"count":"Num_008"}
{"count":"Num_009"}

类似下面的内容,但我确定我不需要依赖 awk。

yes '{}' | head -n10 | jq -c '.count|="Num_ "' | awk '{printf("%s%03i%s\n",,NR-1,)}'

到目前为止,我已经找到了一种方法来计算我的对象,但感觉非常浪费,因为我把所有对象都吞了。

yes '{}' | head -n10 | jq -c -s 'range(0;.|length) as $i|(.[$i]|.count|=$i)'

我会继续玩这个,但我认为这是我学习的机会。我有什么想法可以更有效地做到这一点吗?

我还想出了一种格式化字符串的 hack-y 方法,因为我假设我的流中有 < 1000 个对象。

yes '{}' | head -n20 | jq -c -s 'range(0;.|length) as $i|(.[$i]|.count|=(1000+$i|tostring|ltrimstr("1")|"Num_"+.))'

使用 -s (slurp) 选项,您可以执行以下操作:

yes '{}' | head -n10 | jq -s 'to_entries | map(.value.count = .key)[].value'

但是,是的,正如您自己所说,吸食是一种浪费;更糟糕的是,它会阻塞流。

你可以做的是,对于每个元素,将它压缩成一行(通过 jq -c '.' 进行管道传输;你的 "yes" 对象示例不需要它,但是任意来自管道的对象可能) 然后在你的 shell 上迭代它。在鱼 shell 上,但很容易移植到其他任何地方:

set j 0
for i in (yes '{}' | head -n 100000 | jq -c '.')
  set j (expr $j + 1)
  echo $i | jq --arg j $j '.count = ($j | tonumber)'
end

使用最新版本的 jq(即带有 foreach 和输入),例如 jq 1.5rc1,可以按照以下几行高效且相当优雅地执行任务:

yes 1 | head -n10 |\
 jq -c -n 'foreach inputs as $line (0; .+1; {"count": "Num_\(.)"})'

这里的关键是使用-n选项。