JSON에서 값을 확인하고 jq를 사용하여 다른 키를 변경하는 방법은 무엇입니까?

JSON에서 값을 확인하고 jq를 사용하여 다른 키를 변경하는 방법은 무엇입니까?
[
    {
        "name": "user1",
        "status": "off"
    },
    {
        "name": "user2",
        "status": "off"
    },
    {
        "name": "user3",
        "status": "on"
    }
]

status예를 들어 JSON 파일에서 값을 재귀적으로 검색하고 상태가 있는 모든 값을 off가져오는 방법을 알고 싶습니다 .nameoff

user1또한 합계 user2값을 어떻게 변경합니까 on?

나는 jq및 을 사용하고 있습니다 bash.

답변1

배열의 모든 요소에 표현식을 적용하고 변경된 배열을 가져오려면 를 사용합니다 map(expression).

상태가 있는 모든 항목을 추출합니다 off.

$ jq 'map(select(.status == "off"))' file
[
  {
    "name": "user1",
    "status": "off"
  },
  {
    "name": "user2",
    "status": "off"
  }
]

매핑은 select(.status == "off")다음 요소만 추출(선택)하여 배열을 변경합니다 .status == "off".진짜.

위에서 디코딩된 이름만 추출합니다.

$ jq -r 'map(select(.status == "off"))[].name' file
user1
user2

이전 표현식의 끝에 추가하면 [].name먼저 배열을 개별 항목 집합으로 확장한 다음(이것이 바로 그 []작업입니다) .name각 항목에서 값을 추출합니다.

당신은 또한 사용할 수 있습니다

jq -r 'map(select(.status == "off").name)[]' file

...이름 배열을 생성한 다음 그 배열에서 모든 요소를 ​​추출합니다.

on상태가 있는 모든 항목의 상태를 다음으로 설정합니다 off.

$ jq 'map(select(.status == "off").status = "on")' file
[
  {
    "name": "user1",
    "status": "on"
  },
  {
    "name": "user2",
    "status": "on"
  },
  {
    "name": "user3",
    "status": "on"
  }
]

매핑을 사용하면 상태가 있는 요소의 상태를 select(.status == "off").status = "on"으로 설정하여 배열을 수정합니다.onoff

on명시적 이름 기반 항목의 상태를 다음으로 설정합니다.

$ jq 'map(select(.name == "user1" or .name == "user2").status = "on")' file
[
  {
    "name": "user1",
    "status": "on"
  },
  {
    "name": "user2",
    "status": "on"
  },
  {
    "name": "user3",
    "status": "on"
  }
]

마찬가지지만 표현식에 이름을 하드코딩하지 마세요. 대신 명령줄 끝에 목록으로 제공하십시오( --args이름 목록 은~ 해야 하다명령줄의 마지막 항목입니다):

$ jq 'map(select(IN(.name; $ARGS.positional[])).status = "on")' file --args user1 user2
[
  {
    "name": "user1",
    "status": "on"
  },
  {
    "name": "user2",
    "status": "on"
  },
  {
    "name": "user3",
    "status": "on"
  }
]

주어진 이름 목록은 --args이름이 지정된 배열에서 찾을 수 있습니다 $ARGS.positional.

상황이 IN(a; b)돌아왔네요진짜a세트에 있는 경우 b. $ARGS.positional[]명령줄에 제공된 이름 집합인 검색 집합으로 사용합니다 . 즉, select()여기에서는 명령줄 목록에 이름이 나타나는 요소만 추출하고 이러한 요소의 상태는 로 설정됩니다 on.

IN(a; b)비슷한 이름의 항목과 달리 다음 in(a)을 반환합니다.진짜주어진 값이 객체나 배열의 키나 인덱스로 나타나는 경우 a.

환경모두항목 상태는 다음과 같습니다 on.

$ jq 'map(.status = "on")' file
[
  {
    "name": "user1",
    "status": "on"
  },
  {
    "name": "user2",
    "status": "on"
  },
  {
    "name": "user3",
    "status": "on"
  }
]

댓글의 후속 질문:

이렇게 매칭하고 싶다면 NOT IN(a, b)어떻게 해야 할까요? 분명히 내가 묻는 것은 이와 같은 값을 전달하면 user1를 제외한 모든 것이 꺼진다는 것입니다 user1. 어떻게 해야 하나요?

다음은 명시적 명령문을 사용하여 if특정 이름의 상태를 다음과 같이 변경합니다.onoff

jq '
    map(
        if IN(.name; $ARGS.positional[]) then
            .status = "on"
        else
            .status = "off"
        end
    )' file --args user1

또는 단일 행 레이아웃에서는 다음을 수행합니다.

jq 'map(if IN(.name; $ARGS.positional[]) then .status = "on" else .status = "off" end)' file --args user1

후속 조치를 다음과 같이 해석하면아니요상태에 관계없이 특정 이름의 상태를 변경하고 싶지만 다른 모든 상태는 로 변경하고 싶습니다 off. 이 경우 이전 변형에서 사용된 조건을 무효화할 수 있습니다.

jq 'map(select(IN(.name; $ARGS.positional[]) | not).status = "off")' file --args user1

| not나중에 추가된 내용을 참고하세요 IN(...; ...).

물론 if위의 대부분의 변형에서 명령문을 사용할 수도 있지만 select()가능하면 이를 사용하는 것을 좋아합니다.

관련 정보