development

Unix 도구로 JSON 구문 분석

big-blog 2020. 9. 29. 08:02
반응형

Unix 도구로 JSON 구문 분석


다음과 같이 curl 요청에서 반환 된 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로 수행하는 것보다 훨씬 쉽고 안정적입니다 jq.

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

json모듈을 사용하는 Python과 같이 시스템에 이미 설치되었을 가능성이있는 도구를 사용하여이 작업을 수행 할 수 있으므로 적절한 JSON 파서의 이점을 계속 누리면서 추가 종속성을 피할 수 있습니다. 다음은 원래 JSON을 인코딩해야하며 대부분의 최신 터미널에서도 사용하는 UTF-8을 사용한다고 가정합니다.

파이썬 2 :

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

파이썬 3 :

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

역사적 기록

이 답변은 원래 jsawk를 권장 했지만 여전히 작동하지만 사용하기가 조금 더 번거롭고 jqPython 인터프리터보다 덜 일반적으로 설치되는 독립 실행 형 JavaScript 인터프리터에 따라 달라 지므로 위의 답변이 바람직 할 수 있습니다.

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

이 답변은 원래 질문의 Twitter API를 사용했지만 해당 API가 더 이상 작동하지 않아 테스트를 위해 예제를 복사하기 어렵고 새로운 Twitter API에는 API 키가 필요하므로 GitHub API를 사용하도록 전환했습니다. API 키없이 쉽게 사용할 수 있습니다. 원래 질문에 대한 첫 번째 대답은 다음과 같습니다.

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

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

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

이 정규식은 생각보다 강력합니다. 예를 들어, 쉼표와 이스케이프 된 따옴표가 포함 된 문자열을 처리합니다. 조금 더 작업하면 원자 적이라면 실제로 가치를 추출 할 수있는 것을 만들 수 있다고 생각합니다. (중첩이있는 경우 정규식은 물론 할 수 없습니다.)

그리고 더 깨끗하게 (문자열의 원래 이스케이프를 유지하지만) 다음과 같은 것을 사용할 수 있습니다 | perl -pe 's/"text"://; s/^"//; s/",$//'. (나는 이 분석을 위해 이것을했다 .)

실제 JSON 파서를 사용해야한다고 주장하는 모든 혐오 자에게는 정확함을 위해 필수적이지만

  1. 데이터 정리 버그를 확인하거나 데이터에 대한 일반적인 느낌을 얻기 위해 값을 세는 것과 같은 매우 빠른 분석을 수행하려면 명령 줄에서 무언가를 두드리는 것이 더 빠릅니다. 스크립트를 작성하기 위해 편집기를 여는 것은 산만합니다.
  2. grep -ojson적어도 트윗에 대해이 작업을 수행 할 때 Python 표준 라이브러리 보다 훨씬 빠릅니다 (각각 ~ 2KB). 이것이 json느리기 때문인지 확실하지 않습니다 (언젠가 yajl과 비교해야합니다). 그러나 원칙적으로 정규식은 재귀를 지원해야하는 파서 대신 유한 상태이고 훨씬 더 최적화 가능하기 때문에 더 빠르며,이 경우에는 신경 쓰지 않는 구조를 위해 많은 CPU를 빌드하는 데 소비합니다. (누군가가 적절한 (깊이 제한) JSON 구문 분석을 수행 한 유한 상태 변환기를 작성했다면 환상적 일 것입니다. 그 동안 "grep -o"가 있습니다.)

유지 관리가 가능한 코드를 작성하기 위해 저는 항상 실제 파싱 라이브러리를 사용합니다. 나는 jsawk를 시도하지 않았지만 잘 작동한다면 포인트 # 1을 해결할 것입니다.

마지막으로 더 이상한 해결책은 Python을 사용 json하고 원하는 키를 탭으로 구분 된 열로 추출 하는 스크립트를 작성했습니다 . 그런 다음 awk열에 대한 명명 된 액세스를 허용 하는 래퍼를 통해 파이프합니다 . 여기 : json2tsv 및 tsvawk 스크립트 . 따라서이 예에서는 다음과 같습니다.

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과 Boecko의 리드를 따름 :

$ 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

당신은 할 수 다운로드 jq플랫폼에 대한 바이너리 및 실행 ( chmod +x jq) :

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

"name"json 객체에서 속성을 추출 합니다.

jq홈페이지sedJSON 데이터 와 같다고 말합니다 .


awk를 사용 하는 대신 Python의 JSON 지원을 사용하십시오 !

이 같은:

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

Node.js 사용

시스템에 설치되어 있는 경우 필요한 값을 가져 오기 위해 -pprint 및 -eevaulate 스크립트 플래그 를 사용할 수 있습니다 JSON.parse.

JSON 문자열을 사용하고 { "foo": "bar" }"foo"값을 가져 오는 간단한 예 :

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

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

당신은 발에 총을 쏘는 방법을 물었고 저는 탄약을 제공하기 위해 왔습니다 :

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 사용

.bash_rc 파일에 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"
}

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

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;'

또는 CLI 상수 STDIN 에서 fgets 및 이미 열린 스트림을 사용하여 지적했습니다 .

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

nJoy!


기본 Bash 버전 : 백 슬래시 (\) 및 따옴표 ( ") 와도 잘 작동합니다.

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

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]);"

불행히도 사용하는 최고 투표 답변 은 내 시나리오에서 작동하지 않은 전체 일치를 grep반환 하지만 JSON 형식이 일정하게 유지된다는 것을 알고 있다면 lookbehindlookahead 를 사용하여 원하는 값만 추출 할 수 있습니다 .

# 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

이제 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 구문 분석이 그 중 몇 가지입니다. 크로스 플랫폼 버전 https://github.com/PowerShell/PowerShell에 대한 GitHub 페이지입니다.


누군가 중첩 된 구조없이 간단한 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

여기서는 어떤 답도 사용할 수 없습니다. 사용 가능한 jq 없음, 셸 배열 없음, 선언 없음, grep 없음 -P 없음, 룩 비하인드 및 룩어 헤드 없음, Python 없음, Perl 없음, Ruby 없음, 없음-Bash도 없음 ... 남은 답변은 단순히 잘 작동하지 않습니다. 자바 스크립트는 익숙한 것처럼 들리지만 주석은 Nescaffe라고 말합니다. 그래서 그것도 안됩니다. :) 가능하더라도, 내 간단한 필요를 위해-그들은 과도하고 느릴 것입니다.

그러나 모뎀의 json 형식 응답에서 많은 변수를 얻는 것이 매우 중요합니다. 나는 라우터에서 BusyBox를 매우 잘려서 sh에서하고 있습니다! 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 == "login") { print "Login=\""$4"\"" }
    if ($2 == "name") { print "Name=\""$4"\"" }
    if ($2 == "updated_at") { print "Updated=\""$4"\"" }
}' )
echo "$Login, $Name, $Updated"

내부 공백에 문제가 없습니다. 필자의 경우 동일한 명령이 긴 한 줄 출력을 구문 분석합니다. eval이 사용되므로이 솔루션은 신뢰할 수있는 데이터에만 적합합니다. 인용되지 않은 데이터를 수집하도록 조정하는 것은 간단합니다. 많은 변수의 경우 else if를 사용하여 한계 속도 이득을 얻을 수 있습니다. 배열이 없다는 것은 명백히 : 추가 조작없이 여러 레코드가 없음을 의미합니다. 그러나 어레이를 사용할 수있는 경우이 솔루션을 적용하는 것은 간단한 작업입니다.

@maikel sed 대답은 거의 작동합니다 (하지만 그것에 대해 언급 할 수는 없습니다). 내 멋진 형식의 데이터의 경우 작동합니다. 여기에 사용 된 예는 그다지 많지 않습니다 (누락 된 따옴표는 그것을 버립니다). 복잡하고 수정하기 어렵습니다. 또한 11 개의 변수를 추출하기 위해 11 번의 호출을하는 것을 좋아하지 않습니다. 왜? 9 개의 변수를 추출하는 100 개의 루프 시간을 측정했습니다. sed 함수에는 48.99 초가 걸렸고 내 솔루션에는 0.91 초가 걸렸습니다! 공정하지 않아? 9 개 변수의 단일 추출 : 0.51 대 0.02 초.


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

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

xml 파일도 가지고있는 사람은 내 Xidel 을보고 싶을 수 있습니다 . CLI, 종속성이없는 JSONiq 프로세서입니다. (즉, xml 또는 json 처리를위한 XQuery도 지원합니다)

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

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

또는 내 자신의 비표준 확장 구문으로 :

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

json 문자열에서 속성을 얻는 더 쉬운 방법이 있습니다. package.json파일을 예로 사용하여 다음을 시도하십시오.

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

process.env악의적 인 콘텐츠가 인용을 벗어나 코드로 파싱 될 위험없이 파일의 콘텐츠를 node.js에 문자열로 가져 오기 때문에 사용 하고 있습니다.


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 -s 'http://twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '$1~/"text"/ {print}'

더 복잡한 JSON 구문 분석을 위해 python jsonpath 모듈 (Stefan Goessner 작성)을 사용하는 것이 좋습니다.

  1. 설치-

sudo easy_install -U jsonpath

  1. 그걸 써 -

예제 file.json ( http://goessner.net/articles/JsonPath에서 )-

{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

구문 분석 (가격이 10 미만인 모든 책 제목 추출)-

$ cat file.json | python -c "import sys, json, jsonpath; print '\n'.join(jsonpath.jsonpath(json.load(sys.stdin), 'store.book[?(@.price < 10)].title'))"

출력됩니다-

Sayings of the Century
Moby Dick

참고 : 위의 명령 줄에는 오류 검사가 포함되어 있지 않습니다. 오류 검사가있는 완전한 솔루션을 얻으려면 작은 파이썬 스크립트를 만들고 try-except로 코드를 래핑해야합니다.


PHP 가있는 경우 :

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

예를 들어,
json에 국가 ISO 코드 ( http://country.io/iso3.json) 를 제공하는 리소스가 있으며 curl을 사용하여 쉘에서 쉽게 볼 수 있습니다.

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',
  ...

중첩 배열이있는 경우이 출력이 훨씬 더 좋아 보일 것입니다.

이것이 도움이되기를 바랍니다 ...


이것은 또 다른입니다 bashpython하이브리드 대답. 더 복잡한 JSON 출력을 처리하고 싶었지만 bash 애플리케이션의 복잡성을 줄이고 싶었 기 때문에이 답변을 게시했습니다. http://www.arcgis.com/sharing/rest/info?f=json 에서 다음 JSON 개체를 열고 싶습니다 bash.

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

이 접근 방식은 Python 함수의 복잡성을 증가 시키지만 bash 사용은 더 간단 해집니다.

function jsonGet {
  python -c 'import json,sys
o=json.load(sys.stdin)
k="'$1'"
if k != "":
  for a in k.split("."):
    if isinstance(o, dict):
      o=o[a] if a in o else ""
    elif isinstance(o, list):
      if a == "length":
        o=str(len(o))
      elif a == "join":
        o=",".join(o)
      else:
        o=o[int(a)]
    else:
      o=""
if isinstance(o, str) or isinstance(o, unicode):
  print o
else:
  print json.dumps(o)
'
}

curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo.tokenServicesUrl

위 스크립트의 출력은 다음과 같습니다.

배열에 대한 지원을 추가 했으므로 사용할 수 .length있으며 소스가 문자열 배열 인 경우 다음을 사용할 수 있습니다 .join.

curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.23

출력되는 내용 :

  • 1
  • [{ "scale": 591657527.591555, "해상도": 156543.03392800014, "level": 0}, { "scale": 295828763.795777, "해상도": 78271.51696399994, "level": 1}, { "scale": 147914381.897889, "해상도 ": 39135.75848200009,"레벨 ": 2}, {"스케일 ": 73957190.948944,"해상도 ": 19567.87924099992,"레벨 ": 3}, {"스케일 ": 36978595.474472,"해상도 ": 9783.93962049996,"레벨 ": 4} , { "scale": 18489297.737236, "해상도": 4891.96981024998, "level": 5}, { "scale": 9244648.868618, "해상도": 2445.98490512499, "level": 6}, { "scale": 4622324.434309, "해상도 ": 1222.992452562495,"레벨 ": 7}, {"스케일 ": 2311162.217155,"해상도": 611.4962262813797, "레벨": 8}, { "스케일": 1155581.108577, "해상도": 305.74811314055756, "레벨": 9}, { "스케일": 577790.554289, "해상도": 152.87405657041106, "레벨": 10}, { "scale": 288895.277144, "해상도": 76.43702828507324, "level": 11}, { "scale": 144447.638572, "해상도": 38.21851414253662, "level": 12}, { "scale": 72223.819286, "해상도": 19.10925707126831, "레벨": 13}, { "scale": 36111.909643, "해상도": 9.554628535634155, "레벨": 14}, { "scale": 18055.954822, "해상도": 4.77731426794937, "레벨": 15}, { "scale": 9027.977411, "해상도": 2.388657133974685,"레벨": 16}, { "스케일": 4513.988705, "해상도": 1.1943285668550503, "레벨": 17}, { "스케일": 2256.994353, "해상도": 0.5971642835598172, "레벨": 18}, { "스케일 ": 1128.497176,"해상도 ": 0.29858214164761665,"레벨 ": 19}, {"스케일 ": 564.248588,"해상도 ": 0.14929107082380833,"레벨 ": 20}, {"스케일 ": 282.124294,"해상도 ": 0.07464553541190416, "level": 21}, { "scale": 141.062147, "resolution": 0.03732276770595208, "level": 22}, { "scale": 70.5310735, "분해능": 0.01866138385297604, "level": 23}]scale ": 2256.994353,"해상도 ": 0.5971642835598172,"level ": 18}, {"scale ": 1128.497176,"해상도 ": 0.29858214164761665,"level ": 19}, {"scale ": 564.248588,"해상도 ": 0.14929107082380833 , "level": 20}, { "scale": 282.124294, "resolution": 0.07464553541190416, "level": 21}, { "scale": 141.062147, "해상도": 0.03732276770595208, "레벨": 22}, { " scale ": 70.5310735,"해상도 ": 0.01866138385297604,"레벨 ": 23}]scale ": 2256.994353,"해상도 ": 0.5971642835598172,"level ": 18}, {"scale ": 1128.497176,"해상도 ": 0.29858214164761665,"level ": 19}, {"scale ": 564.248588,"해상도 ": 0.14929107082380833 , "level": 20}, { "scale": 282.124294, "resolution": 0.07464553541190416, "level": 21}, { "scale": 141.062147, "해상도": 0.03732276770595208, "레벨": 22}, { " scale ": 70.5310735,"해상도 ": 0.01866138385297604,"레벨 ": 23}]14929107082380833, "레벨": 20}, { "scale": 282.124294, "해상도": 0.07464553541190416, "레벨": 21}, { "scale": 141.062147, "해상도": 0.03732276770595208, "레벨": 22}, { "scale": 70.5310735, "해상도": 0.01866138385297604, "레벨": 23}]14929107082380833, "레벨": 20}, { "scale": 282.124294, "해상도": 0.07464553541190416, "레벨": 21}, { "scale": 141.062147, "해상도": 0.03732276770595208, "레벨": 22}, { "scale": 70.5310735, "해상도": 0.01866138385297604, "레벨": 23}]
  • 24
  • { "scale": 70.5310735, "해상도": 0.01866138385297604, "레벨": 23}

매우 간단하지만 강력한 JSON CLI 처리 도구 인 fx도 있습니다https://github.com/antonmedv/fx

Bash 터미널의 JSON 형식 예

익명 기능 사용 :

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

익명 함수 param => ...를 전달하지 않으면 코드가 자동으로 익명 함수로 변환됩니다. 그리고 다음 키워드로 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 . 새로운 구문을 배울 필요가 없습니다.


업데이트 2018-11-06

fx이제 대화 형 모드 ( ! )가 있습니다.

https://github.com/antonmedv/fx


JSON 구문 분석은 쉘 스크립트에서 고통 스럽습니다. 더 적절한 언어를 사용하여 쉘 스크립팅 규칙과 일치하는 방식으로 JSON 속성을 추출하는 도구를 작성하십시오. 새 도구를 사용하여 즉각적인 쉘 스크립팅 문제를 해결 한 다음 향후 상황을 위해 키트에 추가 할 수 있습니다.

예를 들어, 고려 도구 jsonlookup 같은 내가 말할 경우 그 jsonlookup access token id는 속성 돌아갑니다 ID 속성에 정의 된 토큰 속성 내에서 정의 된 접근 아마도 JSON 데이터입니다 표준 입력에서을. 속성이 없으면 도구는 아무 것도 반환하지 않습니다 (종료 상태 1). 구문 분석에 실패하면 상태 2를 종료하고 stderr에 메시지를 보냅니다. 조회가 성공하면 도구는 속성 값을 인쇄합니다.

JSON 값을 추출하는 정확한 목적을 위해 유닉스 도구를 만들었으므로 쉘 스크립트에서 쉽게 사용할 수 있습니다.

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

모든 언어는 jsonlookup 구현을 위해 수행 됩니다 . 다음은 상당히 간결한 파이썬 버전입니다.

#!/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

파이썬을 사용하는 두 줄. 단일 .sh 파일을 작성하고 다른 .py 파일에 의존하고 싶지 않은 경우 특히 잘 작동합니다. 또한 pipe 사용을 활용합니다 |. echo "{\"field\": \"value\"}"json을 stdout에 인쇄하는 것으로 대체 할 수 있습니다.

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

이것은 pythonpy 의 좋은 사용 사례입니다 .

curl 'http://twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'

경우는 pip다음 시스템에 avaiable이다입니다 :

$ pip install json-query

사용 예 :

$ curl -s http://0/file.json | json-query
{
    "key":"value"    
}

$ curl -s http://0/file.json | json-query my.key
value

$ curl -s http://0/file.json | json-query my.keys.
key_1
key_2
key_3

$ curl -s http://0/file.json | json-query my.keys.2
value_2

참고 URL : https://stackoverflow.com/questions/1955505/parsing-json-with-unix-tools

반응형