jq:在字段中生成UUID

6

我需要为记录唯一地打上UUID标记(用于关联ID)。我无法看到直接通过选项完成此操作的方法,这种操作是否可能?如果不可能,是否有一些解决方法可以实现此目的?

在jq中生成随机数或字符串是否可能?

2个回答

4
如提供一个初始随机数(--argjson initialRandomNumber),在jq中可以生成伪随机数,使用$RANDOM$RANDOM代替$RANDOM旨在增加初始伪随机值的范围。我使用了 Rosettacode jq: random numbersnextRandomNumber 函数的略微修改版本,如下代码所示,用于生成随机数字、字符串和 UUID。每个函数都接受一个参数 $state 并在响应中提供一个新状态 newState 以供后续调用。因为您询问如何生成:1. 随机数,2. 随机字符串,3. UUID,因此您可以在我的代码中找到 6 个函数来生成单个实例和数组。您可以选择需要的函数并将其用作jq过滤器。
#!/bin/bash

jq -c -r -n --argjson initialRandomNumber "$RANDOM$RANDOM" '
  # 15-bit integers generated using the same formula as rand() from the Microsoft C Runtime.
  # The random numbers are in [0 -- 32767] inclusive.
  #
  # Input: 
  #   first call:      $state = a random number provided to jq by parameter
  #   subsequent call: $state = "newState" from last response
  #
  # Output: 
  #   object with pseudo-random number and "newState" for a subsequent call.
  def nextRandomNumber($state):
    ( (214013 * $state) + 2531011) % 2147483648 # mod 2^31
    | { newState: .,
        randomNumber: (. / 65536 | floor) };

  def nextRandomNumbers($state; $count):
    [foreach range($count) as $x (nextRandomNumber($state); nextRandomNumber(.newState); .)]
    | { newState: .[-1].newState,
        randomNumbers: map(.randomNumber) };


# ----- random UUID ---------------

  def hexByte:
    [. / 256 % 16, . % 16]
    | map(if . < 10 then . + 48 else . + 87 end)   # ASCII: 0...9: 48-57, a...f: 97-102
    | implode;

  def nextRandomUUID($state):
    nextRandomNumbers($state; 16)
    | .newState as $newState
    | .randomNumbers
    | map(hexByte)
    | "\(.[0:4] | join(""))-\(.[4:6] | join(""))-\(.[6:8] | join(""))-\(.[8:10] | join(""))-\(.[10:] | join(""))"
    | { newState: $newState,
        randomUUID: . };

  def nextRandomUUIDs($state; $count):
    [foreach range($count) as $x (nextRandomUUID($state); nextRandomUUID(.newState); .)]
    | { newState: .[-1].newState,
        randomUUIDs: map(.randomUUID) };


# ----- random String ---------------

  def letter:
    . % 52
    | [if . < 26 then . + 65 else . + 71 end]   # ASCII: A...Z: 65-90, a...z: 97-122
    | implode;

  def nextRandomString($state; $minLength; $maxLength):
    nextRandomNumber($state)
    | (try (.randomNumber % ($maxLength - $minLength + 1) + $minLength) catch $minLength) as $length
    | nextRandomNumbers(.newState; $length)
    | .newState as $newState
    | .randomNumbers
    | map(letter)
    | join("")
    | { newState: $newState,
        randomString: . };

  def nextRandomStrings($state; $count; $minLength; $maxLength):
    [foreach range($count) as $x (nextRandomString($state; $minLength; $maxLength); nextRandomString(.newState; $minLength; $maxLength); .)]
    | { newState: .[-1].newState,
        randomStrings: map(.randomString) };


# ----- example usage ---------------

  nextRandomNumber($initialRandomNumber)               # see output 1
# nextRandomNumbers($initialRandomNumber; 3)           # see output 2
# nextRandomUUID($initialRandomNumber)                 # see output 3
# nextRandomUUIDs($initialRandomNumber; 3)             # see output 4
# nextRandomString($initialRandomNumber; 10; 15)       # see output 5
# nextRandomStrings($initialRandomNumber; 3; 6; 10)    # see output 6
# nextRandomNumber($initialRandomNumber) | nextRandomNumbers(.newState; 3)   # see output 7
'

输出

输出 1: 生成伪随机数

{"newState":912028498,"randomNumber":13916}

输出2:生成3个伪随机数

{"newState":677282016,"randomNumbers":[10202,20943,6980]}`

输出 3: 生成随机 UUID

{"newState":1188119770,"randomUUID":"cdcda95b-af57-1303-da72-d21c6e7b1861"}

输出 4:生成 3 个随机 UUID

{"newState":907540185,"randomUUIDs":["855c1445-b529-4301-a535-20cb298feaff","5b685e49-8596-830e-f56a-0a22c43c4c32","35fed6d8-d72b-2833-fd6f-f99154358067"]}

输出 5: 生成长度为10-15的随机字符串

{"newState":1037126684,"randomString":"SJadqPGkERAu"}`

输出 6: 随机生成3个长度在6-10之间的字符串。

{"newState":316121190,"randomStrings":["eNKxechu","XPkvNg","TIABHbYCxB"]}`

输出 7: 使用newState来生成第二次调用生成 3 个随机数

{"newState":808494511,"randomNumbers":[26045,16811,12336]}`

3

目前 jq 不支持 UUID 生成,因此最好的方法是将 UUID 输入 jq,例如:

ruby -e 'require "securerandom"; p SecureRandom.uuid' | jq '{uuid: .}'
{
  "uuid": "5657dd65-a495-4487-9887-c7f0e01645c9"
}

很遗憾,jq的PRNG贡献尚未被纳入官方发布。关于在jq中编写的PRNG生成器的示例,请参见rosettacode。

https://rosettacode.org/wiki/Linear_congruential_generator#jq

从无限流中读取UUID

假设有一个uuid生成器,比如uuidgen,您可以使用以下方式之一的inputinputs

jq -nR '[range(0;10) | input]' < <(while true; do uuidgen ; done)

(注意这里避免了使用操作系统的管道。)


谢谢,但是在我的情况下,我有一个非常大的json文件,其中包含许多单独的对象,我需要为每个对象添加uuid。我无法将所有数据都读入内存,并且在处理之前,我不一定知道文件中有多少个json对象。有没有办法使用jq生成无限的uuid流,并将其加入到每个json对象中而不需要一次性读入? - the4thamigo_uk
我会使用--argfile(或者也许是--slurpfile)读取JSON,并使用input或inputs读取无限流的UUID,就像在更新后的答案中所示。 - peak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接