programing

Unix 툴을 사용한JSON 해석

sourcejob 2023. 2. 12. 10:23
반응형

Unix 툴을 사용한JSON 해석

컬 요청에서 반환된 JSON을 다음과 같이 해석하려고 합니다.

curl 'http://twitter.com/users/username.json' |
    sed -e 's/[{}]/''/g' | 
    awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'

위의 예에서는 JSON을 여러 필드로 나눕니다.

% ...
"geo_enabled":false
"friends_count":245
"profile_text_color":"000000"
"status":"in_reply_to_screen_name":null
"source":"web"
"truncated":false
"text":"My status"
"favorited":false
% ...

필드(「」(「」로를 인쇄하려면 해야 합니다.-v k=text

명령줄에서 JSON을 조작하기 위해 특별히 설계된 툴이 많이 있습니다.이 툴은 Awk를 사용하는 것보다 훨씬 쉽고 신뢰성이 높아집니다.

curl -s 'https://api.github.com/users/lambda' | jq -r '.name'

모듈을 사용하는 Python과 같이 시스템에 이미 설치되어 있을 가능성이 높은 툴을 사용하여 적절한 JSON 파서의 이점을 유지하면서 추가 종속성을 방지할 수도 있습니다.다음은 UTF-8을 사용하는 것을 전제로 하고 있습니다.UTF-8은 원래 JSON이 부호화되어야 하며 대부분의 최신 단말기가 사용하는 것입니다.

Python 3:

curl -s 'https://api.github.com/users/lambda' | \
    python3 -c "import sys, json; print(json.load(sys.stdin)['name'])"

Python 2:

export PYTHONIOENCODING=utf8
curl -s 'https://api.github.com/users/lambda' | \
    python2 -c "import sys, json; print json.load(sys.stdin)['name']"

자주 묻는 질문

왜 순수한 셸 솔루션이 아닐까요?

표준 POSIX/Single Unix Specification 쉘은 시퀀스(리스트 또는 어레이) 또는 관련 배열(다른 언어로는 해시 테이블, 맵, 딕트 또는 오브젝트라고도 함)을 나타내는 기능을 포함하지 않는 매우 제한된 언어입니다.이로 인해 휴대용 셸 스크립트에서 JSON의 해석 결과를 나타내는 것이 다소 까다로워집니다.이 방법에는 다소 해킹 방법이 있지만, 키나 값에 특정 특수 문자가 포함되어 있으면 많은 방법이 깨질 수 있습니다.

Bash 4 이상에서는 zsh 및 ksh가 어레이 및 관련 어레이를 지원하지만 일반적으로 이러한 셸을 사용할 수 없습니다(macOS는 GPLv2에서 GPLv3로 변경되었기 때문에 Bash 3에서 Bash 업데이트를 중지했지만 많은 Linux 시스템에는 즉시 zsh가 설치되어 있지 않습니다).오늘날 대부분의 MacOS, Linux 및 BSD 시스템에서 사용할 수 있는 Bash 4 또는 zsh에서 사용할 수 있는 스크립트를 작성할 수 있지만 이러한 다중 언어 스크립트에서 사용할 수 있는 shebang 라인을 작성하는 것은 어렵습니다.

마지막으로 완전한 JSON 파서를 셸에 쓰는 것은 jq나 Python과 같은 기존 종속성을 사용하는 것이 좋을 정도로 중요한 종속성이 됩니다.한 줄짜리나 다섯 줄짜리 작은 조각이 아니라 제대로 구현될 수 있습니다.

awk, sed, 또는 grep를 사용하면 어떨까요?

이러한 도구를 사용하여 JSON에서 기존의 셰이프를 사용하여 한 줄에 한 개의 키와 같이 알려진 방법으로 포맷된 빠른 추출을 수행할 수 있습니다.다른 답변에는 이에 대한 제안의 몇 가지 예가 있습니다.

다만, 이러한 툴은 행 베이스 또는 레코드 베이스의 형식용으로 설계되어 있습니다.일치된 딜리미터와 이스케이프 문자를 재귀적으로 해석하기 위한 것은 아닙니다.

따라서 awk/sed/grep를 사용하는 이러한 빠르고 더러운 솔루션은 취약할 수 있으며 공백이 축소되거나 JSON 개체에 중첩 수준이 추가되거나 문자열 내에서 이스케이프된 따옴표가 추가되는 등 입력 형식의 일부 측면이 변경되면 깨질 수 있습니다. 없이 할 수 에 JSON에 대한 .jq파이썬

이전에도 셸 스크립트의 입력 해석 불량으로 대량의 고객 데이터가 삭제되는 문제에 대처한 적이 있기 때문에, 이러한 취약성이 있는 빠르고 더러운 방법은 추천하지 않습니다.일회성 처리를 하고 있는 경우는, 다른 회답을 참조해 주세요.다만, 기존의 테스트 끝난 JSON 파서를 사용하는 것을 강하게 추천합니다.

이력 메모

이 답변은 원래 jsawk를 권장했는데, 여전히 작동해야 하지만 사용하기가 좀 더 번거롭습니다.jqPython 인터프리터보다 덜 일반적인 스탠드아론 JavaScript 인터프리터에 의존하기 때문에 위의 답변이 바람직할 수 있습니다.

curl -s 'https://api.github.com/users/lambda' | jsawk -a 'return this.name'

이 답변도 원래 질문에서 Twitter API를 사용했지만 API가 작동하지 않아 테스트하기 위한 예시를 복사하기 어렵고, 새로운 Twitter API는 API 키가 필요하기 때문에 API 키 없이도 쉽게 사용할 수 있는 GitHub API로 바꿨습니다.첫 번째 질문에 대한 답변은 다음과 같습니다.

curl 'http://twitter.com/users/username.json' | jq -r '.text'

특정 키의 값을 빠르게 추출하기 위해 개인적으로는 regex의 일치만 반환하는 "grep -o"를 사용합니다.예를 들어 트윗에서 "텍스트" 필드를 가져오려면 다음과 같이 하십시오.

grep -Po '"text":.*?[^\\]",' tweets.json

이 regex는 생각보다 강력합니다.예를 들어 콤마와 이스케이프 따옴표가 포함된 문자열에 대해 적절하게 처리합니다.조금 더 연구하면 원자라면 가치를 추출할 수 있는 것을 만들 수 있을 것 같습니다.(네스팅이 있는 경우 regex는 물론 할 수 없습니다.

더 하기 의 원래 부분이 빠져나가지 ) 과 같이 사용할 수 | perl -pe 's/"text"://; s/^"//; s/",$//'( 분석을 위해 이 작업을 수행했습니다.)

진짜 JSON 파서를 사용해야 한다고 주장하는 모든 악플러에게 - 네, 정확성을 위해 필수적입니다.

  1. 데이터 클리닝 버그를 체크하거나 데이터에 대한 일반적인 느낌을 얻기 위해 값을 세는 등 매우 빠른 분석을 수행하려면 명령줄에서 무언가를 두드리는 것이 더 빠릅니다.스크립트를 작성하기 위해 편집기를 여는 것은 주의를 산만하게 한다.
  2. grep -o Python보다 입니다.json적어도 트윗(각각 최대 2KB)에 대해 이 작업을 수행하는 경우 라이브러리.이게 단지 그 이유 때문인지는 모르겠지만jsonCPU の 이이이이이 -o )가

유지관리 가능한 코드를 작성하기 위해 항상 실제 구문 분석 라이브러리를 사용합니다.는 jsawk을 시도하지 않았지만, 잘 작동한다면, 그것이 1번 포인트를 해결할 수 있습니다.

Python Python을 사용한 스크립트했습니다.json열로 랩퍼를 하여 탭으로 구분합니다.awk컬럼에 대한 이름 있는 접근을 허용합니다.여기서는 json2tsvtsvawk 스크립트입니다.따라서 이 예에서는 다음과 같습니다.

json2tsv id text < tweets.json | tsvawk '{print "tweet " $id " is: " $text}'

이 접근방식은 #2를 다루지 않고 단일 Python 스크립트보다 비효율적이며 약간 취약합니다. 문자열 값의 줄 바꿈과 탭 정규화를 강제하여 awk의 필드/레코드 구분된 세계관과 잘 어울립니다., 유지할 수 .커맨드라인에 이 높아집니다.grep -o.

(특히 코멘트에서) Python을 사용할 것을 제안하는 몇 가지 권장사항을 바탕으로, 저는 예를 찾지 못한 것에 실망했습니다.

JSON 데이터에서 단일 값을 얻을 수 있는 단일 라인입니다.데이터를 (어디서부터) 배관하고 있는 것을 전제로 하고 있기 때문에 스크립팅 컨텍스트에서 도움이 됩니다.

echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hostname"]'

martinr와 Bocko의 리더에 이어:

curl -s 'http://twitter.com/users/username.json' | python -mjson.tool

그러면 GREP 친화적인 출력이 됩니다.매우 편리함:

curl -s 'http://twitter.com/users/username.json' | python -mjson.tool | grep my_key

플랫폼용 바이너리를 다운로드하여 실행할 수 있습니다(chmod +x jq

$ curl 'https://twitter.com/users/username.json' | ./jq -r '.name'

"name"속성을 지정합니다.

jq 홈페이지는 마치sedJSON の j j j j j 。

Node.js 사용방법

시스템에 Node.js가 설치되어 있으면-p 및 쇄쇄-e스크립트 플래그를 사용하여 필요한 값을 추출합니다.

스트링 JSON을 한 예{ "foo": "bar" }foo의.

node -pe 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'

출력:

bar

우리는 냐하 to to to에 할 수 입니다.cat파일에는 다음과 같은 유틸리티를 사용할 수 있습니다.

node -pe 'JSON.parse(process.argv[1]).foo' "$(cat foobar.json)"

출력:

bar

또는 JSON을 포함하는 URL과 같은 다른 형식:

node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"

출력:

Trevor Senior

AWK 대신 Python의 JSON 지원을 사용하세요!

다음과 같은 경우:

curl -s http://twitter.com/users/username.json | \
    python -c "import json,sys;obj=json.load(sys.stdin);print(obj['name']);"

macOS v12.3(Monterey)이 삭제되었으므로 를 사용해야 합니다./usr/bin/python3(MacOS v12.3 이))

curl -s http://twitter.com/users/username.json | \
    python3 -c "import json,sys;obj=json.load(sys.stdin);print(obj['name']);"

발밑에 총을 쏘는 방법을 물으셨고, 저는 탄약을 제공하러 왔습니다.

curl -s 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^text/ {print $2}'

하면 .tr -d '{}'sed하지만 이들을 완전히 배제하는 것도 바람직한 결과를 가져오는 것 같다.

를 파이프로 하세요.sed 's/\(^"\|"$\)//g'

다른 사람들은 충분히 경각심을 가지고 있다고 생각한다.구급차를 부르기 위해 휴대 전화를 가지고 대기하고 있겠습니다.준비되었을 때 사격해라.

Python에서의 Bash 사용

.bashrc 파일에 Bash 함수를 만듭니다.

function getJsonVal () {
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}

그리고나서

curl 'http://twitter.com/users/username.json' | getJsonVal "['text']"

출력:

My status

여기에도 같은 기능이 있습니다만, 에러 체크가 포함되어 있습니다.

function getJsonVal() {
   if [ \( $# -ne 1 \) -o \( -t 0 \) ]; then
       cat <<EOF
Usage: getJsonVal 'key' < /tmp/
 -- or --
 cat /tmp/input | getJsonVal 'key'
EOF
       return;
   fi;
   python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}

$# -ne 1은 적어도1개의 입력을 확인하고 -t 0은 파이프에서 리다이렉트하고 있는지 확인합니다.

이 구현의 장점은 중첩된 JSON 값에 액세스하여 JSON 콘텐츠를 얻을 수 있다는 것입니다.=)

예:

echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']['a'][1]"

출력:

2

정말 화려하게 꾸미고 싶다면 데이터를 인쇄할 수 있습니다.

function getJsonVal () {
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1, sort_keys=True, indent=4))";
}

echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']"
{
    "a": [
        1,
        2,
        3
    ],
    "bar": "baz"
}

갱신(2020)

외부 툴(예: Python)의 가장 큰 문제는 패키지 매니저와 의존성을 다루어야 설치된다는 것입니다.

이제 '이렇게'가 생겼으니까jqGitHub Releases 및 Webi(webinstall.dev/jq)를 통해 쉽게 크로스 플랫폼을 설치할 수 있는 스탠드아론의 정적 툴로서 다음을 권장합니다.

Mac, Linux:

curl -sS https://webi.sh/jq | bash

Windows 10:

curl.exe -A MS https://webi.ms/jq | powershell

치트시트: https://webinstall.dev/jq

오리지널 (2011년)

TickTick은 bash로 작성된 JSON 파서(250줄 미만의 코드)입니다.

다음은 Bash가 JSON을 지원하는 세상을 상상해 보세요라는 기사에서 나온 저자의 단편입니다.

#!/bin/bash
. ticktick.sh

``
  people = {
    "Writers": [
      "Rod Serling",
      "Charles Beaumont",
      "Richard Matheson"
    ],
    "Cast": {
      "Rod Serling": { "Episodes": 156 },
      "Martin Landau": { "Episodes": 2 },
      "William Shatner": { "Episodes": 2 }
    }
  }
``

function printDirectors() {
  echo "  The ``people.Directors.length()`` Directors are:"

  for director in ``people.Directors.items()``; do
    printf "    - %s\n" ${!director}
  done
}

`` people.Directors = [ "John Brahm", "Douglas Heyes" ] ``
printDirectors

newDirector="Lamont Johnson"
`` people.Directors.push($newDirector) ``
printDirectors

echo "Shifted: "``people.Directors.shift()``
printDirectors

echo "Popped: "``people.Directors.pop()``
printDirectors

이는 대부분의 배포에서 사용할 수 있는 표준 Unix 도구를 사용합니다.백슬래시(\) 및 따옴표("")에도 잘 작동합니다.

경고:이는 jq의 세기에 근접하지 않으며 매우 단순한 JSON 개체에서만 작동합니다.이는 원래 질문에 답하기 위한 시도이며 추가 도구를 설치할 수 없는 경우입니다.

function parse_json()
{
    echo $1 | \
    sed -e 's/[{}]/''/g' | \
    sed -e 's/", "/'\",\"'/g' | \
    sed -e 's/" ,"/'\",\"'/g' | \
    sed -e 's/" , "/'\",\"'/g' | \
    sed -e 's/","/'\"---SEPERATOR---\"'/g' | \
    awk -F=':' -v RS='---SEPERATOR---' "\$1~/\"$2\"/ {print}" | \
    sed -e "s/\"$2\"://" | \
    tr -d "\n\t" | \
    sed -e 's/\\"/"/g' | \
    sed -e 's/\\\\/\\/g' | \
    sed -e 's/^[ \t]*//g' | \
    sed -e 's/^"//'  -e 's/"$//'
}


parse_json '{"username":"john, doe","email":"john@doe.com"}' username
parse_json '{"username":"john doe","email":"john@doe.com"}' email

--- outputs ---

john, doe
johh@doe.com

PHP CLI를 사용한 JSON 구문 분석

주제에서 벗어난 질문이지만 우선 순위가 지배하고 있기 때문에 이 질문은 신뢰할 수 있는 PHP에 대한 언급이 없으면 불완전합니다. 맞습니까?

같은 예제의 JSON을 사용하고 있습니다만, 불명확함을 줄이기 위해서 변수에 할당합니다.

export JSON='{"hostname":"test","domainname":"example.com"}'

PHP의 장점을 위해 file_get_contentsphp://stdin 스트림 래퍼를 사용하고 있습니다.

echo $JSON | php -r 'echo json_decode(file_get_contents("php://stdin"))->hostname;'

또는 지적한 바와 같이 fget과 CLI 상수 STDIN에서 이미 열린 스트림을 사용합니다.

echo $JSON | php -r 'echo json_decode(fgets(STDIN))->hostname;'

중첩된 구조를 사용하지 않고 단순 JSON 개체에서 값을 추출하려는 경우 Bash를 떠나지 않고 정규 표현을 사용할 수 있습니다.

다음은 JSON 표준에 따라 bash 정규 표현을 사용하여 정의한 함수입니다.

function json_extract() {
  local key=$1
  local json=$2

  local string_regex='"([^"\]|\\.)*"'
  local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
  local value_regex="${string_regex}|${number_regex}|true|false|null"
  local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"

  if [[ ${json} =~ ${pair_regex} ]]; then
    echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
  else
    return 1
  fi
}

주의: 개체 및 어레이는 값으로 지원되지 않지만 표준에서 정의된 다른 모든 값 유형은 지원됩니다.또한 JSON 문서의 깊이가 아무리 깊어도 동일한 키 이름만 있으면 쌍이 일치합니다.

OP의 예를 사용하여:

$ json_extract text "$(curl 'http://twitter.com/users/username.json')"
My status

$ json_extract friends_count "$(curl 'http://twitter.com/users/username.json')"
245

에서는 「」를 사용하고 .grep시나리오에서 작동하지 않은 전체 일치를 반환하지만 JSON 형식이 일정하게 유지된다는 것을 알고 있는 경우 lookbehind와 lookahead사용하여 원하는 값만 추출할 수 있습니다.

# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="FooBar":")(.*?)(?=",)'
he\"llo
# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="TotalPages":)(.*?)(?=,)'
33
#  echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="anotherValue":)(.*?)(?=})'
100

Ruby 및 http://flori.github.com/json/을 사용하는 버전

< file.json ruby -e "require 'rubygems'; require 'json'; puts JSON.pretty_generate(JSON[STDIN.read]);"

또는 보다 간결하게:

< file.json ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"

이것은 또 다른 Bash와 Python의 하이브리드 답입니다.좀 더 복잡한 JSON 출력을 처리하고 싶었지만 bash 어플리케이션의 복잡성을 줄이고 싶어서 이 답변을 올렸습니다.Bash의 http://www.arcgis.com/sharing/rest/info?f=json에서 다음 JSON 개체를 엽니다.

{
  "owningSystemUrl": "http://www.arcgis.com",
  "authInfo": {
    "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
    "isTokenBasedSecurity": true
  }
}

에서는 제가 .jq ★★★★★★★★★★★★★★★★★」unquote파이톤를 Import하면 Import라는 알 수 .json파이썬위의 구문을 참조하려면 다음 구문은 다음과 같습니다.

  • data
  • data[ "authInfo" ]
  • data[ "authInfo" ][ "tokenServicesUrl" ]

바쉬를 할 수 .data파이썬

  • jq
  • jq '[ "authInfo" ]'
  • jq '[ "authInfo" ][ "tokenServicesUrl" ]'

파라미터가 없는 경우 jq는 JSON prettifier로 동작합니다.파라미터를 사용하면 Python 구문을 사용하여 서브 딕셔너리와 어레이 요소 탐색을 포함하여 사전에서 원하는 것을 추출할 수 있습니다.

다음은 Bash Python 하이브리드 함수입니다.

#!/bin/bash -xe

jq_py() {
  cat <<EOF
import json, sys
data = json.load( sys.stdin )
print( json.dumps( data$1, indent = 4 ) )
EOF
}

jq() {
  python -c "$( jq_py "$1" )"
}

unquote_py() {
  cat <<EOF
import json,sys
print( json.load( sys.stdin ) )
EOF
}

unquote() {
  python -c "$( unquote_py )"
}

다음은 Bash Python 함수의 사용 예를 제시하겠습니다.

curl http://www.arcgis.com/sharing/rest/info?f=json | tee arcgis.json
# {"owningSystemUrl":"https://www.arcgis.com","authInfo":{"tokenServicesUrl":"https://www.arcgis.com/sharing/rest/generateToken","isTokenBasedSecurity":true}}

cat arcgis.json | jq
# {
#     "owningSystemUrl": "https://www.arcgis.com",
#     "authInfo": {
#         "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#         "isTokenBasedSecurity": true
#     }
# }

cat arcgis.json | jq '[ "authInfo" ]'
# {
#     "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#     "isTokenBasedSecurity": true
# }

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]'
# "https://www.arcgis.com/sharing/rest/generateToken"

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]' | unquote
# https://www.arcgis.com/sharing/rest/generateToken

JSON 문자열에서 속성을 가져오는 더 쉬운 방법이 있습니다.「」의 package.json예를 들면, 다음과 같이 해 주세요.

#!/usr/bin/env bash
my_val="$(json=$(<package.json) node -pe "JSON.parse(process.env.json)['version']")"

쓰죠.process.env이는 파일의 내용을 문자열로 Node.js에 가져오기 때문에 악의적인 콘텐츠가 인용에서 벗어나 코드로 해석될 위험이 없기 때문입니다.

PowerShell은 크로스 플랫폼이기 때문에 매우 직관적이고 매우 심플하기 때문에 이 방법을 시도해 보려고 합니다.

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json

ConvertFrom-Json은 JSON을 PowerShell 커스텀 객체로 변환하므로 그 시점부터 속성에 대한 작업을 쉽게 수행할 수 있습니다.예를 들어 'id' 속성만 원하는 경우 다음을 수행합니다.

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json | select -ExpandProperty id

모든 것을 Bash 내에서 호출하려면 다음과 같이 호출해야 합니다.

powershell 'curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json'

물론 PowerShell을 사용하면 컬 없이 다음과 같은 작업을 수행할 수 있습니다.

Invoke-WebRequest 'https://api.github.com/users/lambda' | select -ExpandProperty Content | ConvertFrom-Json

마지막으로 커스텀 오브젝트를 JSON으로 쉽게 변환하는 ConvertTo-Json도 있습니다.다음은 예를 제시하겠습니다.

(New-Object PsObject -Property @{ Name = "Tester"; SomeList = @('one','two','three')}) | ConvertTo-Json

이렇게 좋은 JSON을 만들 수 있습니다.

{
"Name":  "Tester",
"SomeList":  [
                 "one",
                 "two",
                 "three"
             ]

}

물론 Unix에서 Windows 쉘을 사용하는 것은 다소 신성하지 않지만 PowerShell은 몇 가지 점에서 매우 뛰어나고 JSON과 XML을 해석하는 것도 그 중 하나입니다.크로스 플랫폼 버전의 GitHub 페이지는 다음과 같습니다.PowerShell

여기서는 어떤 답변도 사용할 수 없습니다.jq, 셸 어레이, declarate, grep -P, lookbehind, lookahead, Python, Perl, Ruby, 심지어 Bash도 사용할 수 없습니다.

나머지 답변은 제대로 작동하지 않습니다.JavaScript는 익숙하게 들립니다만, 주석에는 Nescaffe라고 쓰여져 있기 때문에, 사용할 수 없다고 해도, 제 단순한 요구에 대해서는, 과잉으로 시간이 걸립니다.

단, 모뎀의 JSON 형식의 응답에서 많은 변수를 얻는 것은 매우 중요합니다. 셸에서 하고 있어요sh라우터에서 Busy Box를 대폭 줄였습니다.AWK만 사용해도 문제가 없습니다.구분자를 설정하고 데이터를 읽기만 하면 됩니다.단일 변수일 경우, 그게 전부입니다!

awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json

어레이가 없는 거 기억해요?AWK 내의 해석 데이터를 셸 스크립트에서 필요한 11개의 변수에 할당해야 했습니다.어디를 보더라도 그건 불가능한 임무라고 했어요.그것도 문제없습니다.

저의 해결책은 간단합니다.이 코드는 다음과 같습니다.

  1. 질문에서 .json 파일을 해석하고(실제로 가장 높은 응답에서 작업 데이터 샘플을 빌렸습니다), 인용된 데이터를 추출합니다.

  2. awk 내에서 셸 변수를 생성하여 이름 있는 셸 변수 이름을 자유롭게 할당합니다.

    eval $( curl - s ' https://api.github.com/users/lambda' | awk ' BEGIN { FS == " , RS == " } , { if $2 == " " $4 " } 인쇄 " = "name" 인쇄 " $2 == "frint " 4 " } 인쇄 " } 인쇄 "Name == " $4" 인쇄 " } 인쇄, $2 == "f $2 == "AUpdateded" 인쇄 " } 인쇄 " } " 。

안에 빈칸은 문제가 없습니다.제 사용법에서는 같은 명령어로 긴 단일 행 출력이 해석됩니다.eval이 사용되므로 이 솔루션은 신뢰할 수 있는 데이터에만 적합합니다.

따옴표가 없는 데이터를 픽업하기 위해 간단하게 조정할 수 있습니다.변수가 많은 경우, 다음과 같은 경우 한계 속도 게인을 달성할 수 있습니다.어레이가 부족하다는 것은 분명합니다.추가 조작 없이 여러 개의 레코드가 필요 없습니다.그러나 어레이를 사용할 수 있는 경우 이 솔루션을 조정하는 것은 간단한 작업입니다.

@maikel의 sed 답변은 거의 효과가 있습니다(단, 코멘트는 할 수 없습니다).포맷이 잘 된 데이터라면 동작합니다.여기서 사용하는 예에서는 그다지 많지 않습니다(따옴표가 누락되어 있으면 지워집니다).그것은 복잡하고 수정하기 어렵다.또한 11개의 변수를 추출하기 위해 11개의 호출을 해야 하는 것도 좋아하지 않습니다.왜요? 9개의 변수를 추출하는 100개의 루프를 측정했습니다. sed 기능은 48.99초, 내 솔루션은 0.91초가 걸렸습니다!불공평해?0.51초 대 0.02초의 9가지 변수를 한 번만 추출합니다.

XML 파일도 가지고 있는 사람이 Xidel을 보고 싶어할지도 몰라.명령줄 인터페이스로 종속성이 없는 JSONiq 프로세서입니다(즉, XML 또는 JSON 처리를 위한 XQuery도 지원합니다).

질문의 예는 다음과 같습니다.

 xidel -e 'json("http://twitter.com/users/username.json")("name")'

또는 비표준 확장 구문을 사용하는 경우:

 xidel -e 'json("http://twitter.com/users/username.json").name'

이런 걸 시도해 볼 수 있어요.

curl -s 'http://twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '$1~/"text"/ {print}'

기존 답변에서 다루지 않은 흥미로운 툴 중 하나는 Go로 작성된 툴입니다.Go에는 "Make JSON greppable!"이라는 태그 라인이 있으며, 이것이 바로 JSON의 기능입니다.

기본적으로는 so서 so so so so so so sogron는 JSON을 개별 할당으로 분할하여 절대적인 '경로'를 표시합니다. 가장 큰 jq 되어 있는지를 을 검색할 수 하고, 일 없이 값을 할 수 있도록 것입니다.

를 들어, 제가 요.'twitter_username', .

% gron 'https://api.github.com/users/lambda' | fgrep 'twitter_username'
json.twitter_username = "unlambda";
% gron 'https://api.github.com/users/lambda' | fgrep 'twitter_username' | gron -u
{
  "twitter_username": "unlambda"
}

그것처럼 간단해.「 」의 다음 .gron -u는 (ungon)은 JSON을 다시 .「 」의 fgrep는, 해, , 으로는 「」라고 하는 로서 평가하는 입니다.grep -F)

중첩된 구조에서 레코드가 어디에 있는지 확인하기 위한 문자열을 검색하는 또 다른 예

% echo '{"foo":{"bar":{"zoo":{"moo":"fine"}}}}' | gron | fgrep "fine"
json.foo.bar.zoo.moo = "fine";

, 「JSON」의 도 서포트하고 있는 .-s명령줄 플래그. 이 플래그에서는 일치하는 레코드를 위해 입력 스트림을 연속적으로 그릴 수 있습니다. 한 also도.gron에는 런타임 의존성이 없습니다.Linux, Mac, 윈도우즈 또는 FreeBSD용 바이너리를 다운로드하여 실행할 수 있습니다.

기타 사용 예시와 트립은 공식 Github 페이지 - Advanced Usage에서 확인할 수 있습니다.

가능한 gron다른 JSON 구문 분석 도구에 대한 자세한 내용은 프로젝트 페이지의 작성자 메모에서 참조하십시오.

왜 그냥 jq를 쓰면 안 되는 거죠?

jq는 훌륭하고 gron보다 훨씬 강력하지만 그 파워는 복잡함을 수반합니다.gron은 grep이나 sed 등 이미 알고 있는 툴을 사용하기 쉽게 하는 것을 목표로 하고 있습니다.

다음을 사용할 수 있습니다.

curl 'http://twitter.com/users/username.json' | jshon -e text

다음은 AWK를 사용하여 수행할 수 있는 한 가지 방법입니다.

curl -sL 'http://twitter.com/users/username.json' | awk -F"," -v k="text" '{
    gsub(/{|}/,"")
    for(i=1;i<=NF;i++){
        if ( $i ~ k ){
            print $i
        }
    }
}'

여기 좋은 참고 자료가 있습니다.이 경우:

curl 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) { where = match(a[i], /\"text\"/); if(where) {print a[i]} }  }'

셸 스크립트에서 JSON을 해석하는 것은 어렵습니다.보다 적절한 언어를 사용하여 셸 스크립팅 규칙과 일치하는 방법으로 JSON 속성을 추출하는 도구를 만듭니다.새로운 툴을 사용하여 셸 스크립팅 문제를 즉시 해결한 후 향후 상황에 대비하여 키트에 추가할 수 있습니다.

예를 들어 툴 json lookup을 생각해 보겠습니다.jsonlookup access token id표준 입력으로부터의 어트리뷰트 액세스내에 정의되고 있는 어트리뷰트 토큰내에 정의되고 있는 어트리뷰트 ID(아마도 JSON 데이터)를 반환합니다.속성이 존재하지 않으면 툴은 아무것도 반환하지 않습니다(종료 상태 1).해석에 실패하면 상태 2를 종료하고 표준 오류 메시지를 표시합니다.조회가 성공하면 도구는 속성 값을 인쇄합니다.

JSON 값을 정확하게 추출하기 위한 Unix 도구를 작성하면 셸 스크립트에서 쉽게 사용할 수 있습니다.

access_token=$(curl <some horrible crap> | jsonlookup access token id)

json lookup 구현에는 어떤 언어라도 상관없습니다.다음은 꽤 간결한 Python 버전입니다.

#!/usr/bin/python

import sys
import json

try: rep = json.loads(sys.stdin.read())
except:
    sys.stderr.write(sys.argv[0] + ": unable to parse JSON from stdin\n")
    sys.exit(2)
for key in sys.argv[1:]:
    if key not in rep:
        sys.exit(1)
    rep = rep[key]
print rep

Python을 사용한 2라인입니다.특히 단일 .sh 파일을 쓸 때 다른 .py 파일에 의존하지 않는 경우에 적합합니다.합니다.|echo "{\"field\": \"value\"}"JSON 파일을 표준 출력으로 인쇄하는 것으로 대체할 수 있습니다.

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'

PHP 인터프리터가 설치되어 있는 경우:

php -r 'var_export(json_decode(`curl http://twitter.com/users/username.json`, 1));'

예를 들어 다음과 같습니다.

JSON 콘텐츠에 각국의 ISO 코드를 제공하는 리소스(http://country.io/iso3.json)가 있으며, 다음과 같이 컬이 있는 쉘에서 쉽게 볼 수 있습니다.

curl http://country.io/iso3.json

하지만 그것은 매우 편리하지 않고 읽을 수 없을 것 같다.JSON 콘텐츠를 보다 잘 해석하여 읽을 수 있는 구조를 확인합니다.

php -r 'var_export(json_decode(`curl http://country.io/iso3.json`, 1));'

이 코드는 다음과 같이 인쇄됩니다.

array (
  'BD' => 'BGD',
  'BE' => 'BEL',
  'BF' => 'BFA',
  'BG' => 'BGR',
  'BA' => 'BIH',
  'BB' => 'BRB',
  'WF' => 'WLF',
  'BL' => 'BLM',
  ...

네스트된 배열이 있는 경우 이 출력이 훨씬 좋아집니다.

매우 심플하지만 강력한 JSON CLI 처리 도구 fx도 있습니다.

Bash 터미널에서의 JSON 포맷 예시

익명 함수 사용:

echo '{"key": "value"}' | fx "x => x.key"

출력:

value

익명 함수 매개 변수 → ...을 전달하지 않으면 코드가 자동으로 익명 함수로 변환됩니다.또, 다음의 키워드로 JSON 에 액세스 할 수 있습니다.

$ echo '[1,2,3]' | fx "this.map(x => x * 2)"
[2, 4, 6]

또는 도트 구문만 사용합니다.

echo '{"items": {"one": 1}}' | fx .items.one

출력:

1

JSON을 줄이기 위해 임의의 수의 익명 함수를 전달할 수 있습니다.

echo '{"items": ["one", "two"]}' | fx "this.items" "this[1]"

출력:

two

확산 연산자를 사용하여 기존 JSON을 업데이트할 수 있습니다.

echo '{"count": 0}' | fx "{...this, count: 1}"

출력:

{"count": 1}

단순한 JavaScript입니다.새로운 구문을 배울 필요가 없습니다.


최신 버전의 fx에는 인터랙티브 모드가 있습니다.

Python 2.7과 3에 대한 바닐라 Linux LSB와 Mac OS 이상의 의존성 없이 실행되며 오류를 처리할 수 있는 짧은 Bash가 필요했습니다. 예를 들어 Python 예외를 입력하지 않고 JSON 구문 분석 오류와 누락된 속성 오류를 보고할 수 있습니다.

json-extract () {
  if [[ "$1" == "" || "$1" == "-h" || "$1" == "-?" || "$1" == "--help" ]] ; then
    echo 'Extract top level property value from json document'
    echo '  Usage: json-extract <property> [ <file-path> ]'
    echo '  Example 1: json-extract status /tmp/response.json'
    echo '  Example 2: echo $JSON_STRING | json-extract status'
    echo '  Status codes: 0 - success, 1 - json parse error, 2 - property missing'
  else
    python -c $'import sys, json;\ntry: obj = json.load(open(sys.argv[2])); \nexcept: sys.exit(1)\ntry: print(obj[sys.argv[1]])\nexcept: sys.exit(2)' "$1" "${2:-/dev/stdin}"
  fi
}

언급URL : https://stackoverflow.com/questions/1955505/parsing-json-with-unix-tools

반응형