【问题标题】:How can I iterate over a shell array of objects and delete them from a JSON file with jq?如何遍历对象的 shell 数组并使用 jq 从 JSON 文件中删除它们?
【发布时间】:2021-11-04 16:51:29
【问题描述】:

我正在尝试从 Slack 的 channels.json 文件中的 json 对象列表中清除非活动通道。我通过检查导出中频道目录中最后一条消息的时间戳并将非活动频道列表写入数组来获得非活动频道列表(定义为过去 90 天内未更新),因为此数据在json 对象本身。唯一的问题是我不知道如何安排它,以便在写入新的输出文件之前从输入中删除数组中的每个通道。请参阅下面我的函数代码中的missing something important here 注释。

这是我当前的功能。

exclude-inactive-channels () {
# Check for a valid argument
  if [ -z $1 ]; then
    echo "No arguments supplied."
    return 1
  elif [ $# -gt 1 ]; then
    echo "Too many arguments supplied."
    return 1
  elif [ ! -f $1 ]; then
    echo "File doesn't exist."
    return 1
  fi

  cutoff_epoch=$(gdate  -d "90 days ago" +'%s')
  inactive_channels=()
  for channel in $(jq -r '.[] | select(.is_archived == false) | .name' $1); do 
    if [[ -d $channel ]]; then
      last_post=$(ls -1 $channel |sort -n |tail -1 |awk -F'.' '{print $1}')
      last_post_epoch=$(gdate -d "$last_post" +'%s')
      if [[ $last_post_epoch -lt $cutoff_epoch ]]; then
          inactive_channels+=("$channel")
          echo -n "Removing $channel directory. Last post is $last_post."
          #rm -rf $channel
          echo -e "\033[0;32m[OK]\033[0m"
      fi
    fi
  done

  echo "Removing inactive channels from $1 and writing output to new-$1."
  for inactive_channel in ${inactive_channels[@]}; do
    # Next line is untested pseudo code
    jq -r '.[] | del(.name == $inactive_channel)' $1 #missing something important here
  done | jq -s > new-${1}

  echo "Replacing $1 with new-$1."
  # mv new-${1} $1
}

调用这个函数:

exclude-inactive-channels channels.json

示例输入:

[
  {
    "id": "",
    "name": "announcements",
    "created": 1500000000,
    "creator": "",
    "is_archived": false,
    "is_general": true,
    "members": [
      "",
  ],
    "pins": [
      {
        "id": "",
        "type": "C",
        "created": 1500000000,
        "user": "",
        "owner": ""
      },
      ],
    "topic": {
      "value": "",
      "creator": "",
      "last_set": 0
    },
    "purpose": {
      "value": "company wide announcements",
      "creator": "",
      "last_set": 1500000000
    }
  },
  {
    "id": "",
    "name": "general",
    "created": 1500000000,
    "creator": "",
    "is_archived": false,
    "is_general": true,
    "members": [
      "",
  ],
    "pins": [
      {
        "id": "",
        "type": "C",
        "created": 1500000000,
        "user": "",
        "owner": ""
      },
      ],
    "topic": {
      "value": "",
      "creator": "",
      "last_set": 0
    },
    "purpose": {
      "value": "general",
      "creator": "",
      "last_set": 1500000000
    }
  },
]

【问题讨论】:

  • 旁白:很多引用错误shellcheck.net 会在这段代码中发现。
  • 另外,请参阅passing bash variable to jq - 特别是您希望看到建议--arg的答案
  • 顺便说一句,您的示例数据中只有两个通道很难证明一个答案可以删除多个命名项目,同时保留未命名的项目。考虑减少虚假数据的数量以使样本输入更紧凑,因此它至少可以有第三个通道。
  • 顺便说一句,您的示例输入 实际上不是有效的 JSON;你有很多非法的杂散逗号。
  • ...我添加了一个提供这样一个例子的答案。 (敲击构建非活动通道的 shell 数组的代码,因为您的问题根本不是 关于 该代码)。

标签: shell jq slack


【解决方案1】:

更有效的方法是一次性删除所有频道,而不是一次删除一个。

# you need to comment one of these out for out.json to not be an empty list
inactive_channels=(
  "announcements"
  "general"
)

jq --rawfile inactive_channel_stream <(printf '%s\0' "${inactive_channels[@]}") '
  # generate an object mapping keys to delete to a truthy value
  INDEX($inactive_channel_stream | split("\u0000")[]; .) as $inactive_channels

  | map(select(($inactive_channels[.name] // false) | not))
' <in.json >out.json

【讨论】:

  • @ikegami,不幸的是,“流”这个词并没有在 jq 的意义上被使用——$inactive_channel_stream 不是 INDEX 所期望的那样的流。
  • @CharlesDuffy 在几次尝试将您的代码合并到我的代码中失败后,我得到了它的工作原理。 @ikegami 的快捷方式导致jq: error (at &lt;stdin&gt;:45720): split input and separator must be strings。另外,关于 shellcheck.net,我使用的是不受支持的 zsh。也许这解释了我的代码中的一些引用错误。无论哪种方式。这解决了我的问题,谢谢。如果您有时间和耐心,您会介意帮助我了解这是如何工作的吗?
  • @Dustin,我不使用/支持/推荐/容忍 zsh;你需要去其他地方寻求相关的建议。 (我在 2000 年代中期使用了一段时间,但发现我的非 zsh shell 代码质量下降了;我不反对尝试纠正 POSIX sh 中的设计错误的 shell,除了当他们使用非常相似的语法导致人们编写看起来与其他shell兼容但实际上充满细微错误的代码时)。
  • @CharlesDuffy 是的,我绝对不希望你支持我的“雪花”外壳。只是解释不同之处。你对zsh提出了一个有效的理由,但我不知道我现在能不能回去。
  • @ikegami,已更新以遵循您的建议;谢谢。
猜你喜欢
  • 1970-01-01
  • 2022-01-15
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多