유닉스 도구로 JSON 파싱


879

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)?


5
어쨌든 좋은 json 파싱이 아닙니다 ... 문자열의 이스케이프 문자는 어떻습니까? 등에 대한 파이썬 답변이 있습니까? (펄 답변도 ...)?
martinr

51
누군가가 "문제 X를 다른 언어 Y로 쉽게 해결할 수있다"고 말할 때마다 "내 툴박스는 손톱을 움직일 수있는 돌만 가지고 있습니다. 왜 다른 것을 귀찮게합니까?"
BryanH

22
@BryanH : 때때로 언어 Y Y가 제안한 사람이 알고있는 언어의 수에 관계없이 특정 문제 X를 해결하기 위해 더 갖추어 질 있습니다.
jfs

15
늦었지만 여기로 간다. grep -Po '"'"version"'"\s*:\s*"\K([^"]*)' package.json. 이것은 grep으로 만 작업을 쉽게 해결하고 간단한 JSON에 완벽하게 작동합니다. 복잡한 JSON의 경우 적절한 파서를 사용해야합니다.
diosney

2
@auser, 제목에서 "sed와 awk로"를 "UNIX 도구로"로 바꾸는 편집을해도 괜찮습니까?
Charles Duffy

답변:


1127

명령 줄에서 JSON을 조작하기 위해 특별히 설계된 여러 가지 도구가 있으며 다음과 같이 Awk로 수행하는 것보다 훨씬 쉽고 안정적입니다 jq.

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

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

파이썬 3 :

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

파이썬 2 :

export PYTHONIOENCODING=utf8
curl -s 'https://api.github.com/users/lambda' | \
    python2 -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'

7
@thrau +1. jq 그것은 저장소에서 사용할 수 있으며 사용하기 매우 쉬우므로 jsawk보다 훨씬 낫습니다. 나는 둘 다 몇 분 동안 테스트, jq이 전투에서 승리
Szymon Sadło

1
Python 2에서 출력을 다른 명령 으로 파이프하는 경우 파이프에서 Python을 사용하므로 print명령문이 항상 ASCII로 인코딩됩니다. PYTHONIOENCODING=<desired codec>명령에 삽입 하여 터미널에 적합한 다른 출력 인코딩을 설정하십시오. Python 3에서이 경우 기본값은 UTF-8입니다 ( print() 함수 사용 ).
Martijn Pieters

1
brew install
Andy Fraley

1
curl -s에 해당 curl --silent하는 반면, jq -r수단 jq --raw-output문자열 따옴표없이 즉.
Stroobandt Serge

python -c "가져 오기 요청; r = requests.get ( ' api.github.com/users/lambda');print r.json () ['name '];" . 가장 간단합니다!
NotTooTechy

276

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

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

이 정규식은 생각보다 강력합니다. 예를 들어, 쉼표가 포함 된 문자열과 따옴표로 이스케이프 된 문자열을 처리합니다. 나는 조금 더 많은 노력을 기울이면 원자 값이라면 실제로 값을 추출 할 수있는 것을 만들 수 있다고 생각합니다. (네 스팅이있는 경우 정규식은 물론 할 수 없습니다.)

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

주장하는 모든 싫어하는 사람들에게는 실제 JSON 파서를 사용해야합니다. 그렇습니다. 정확성에 필수적이지만

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

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

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

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

이 접근법은 # 2를 다루지 않고 단일 Python 스크립트보다 비효율적이며 약간 취합니다. 문자열 값으로 줄 바꿈과 탭을 정규화하여 awk의 필드 / 레코드로 구분 된 세계관을 잘 활용합니다. 그러나 명령 줄에보다 정확한 정확성을 유지할 수 있습니다 grep -o.


11
정수 값을 잊었습니다. grep -Po '"text":(\d*?,|.*?[^\\]",)'
Robert

3
Robert : 맞습니다. 정규식은 해당 필드의 문자열 값으로 만 작성되었습니다. 당신이 말하는대로 정수를 추가 할 수 있습니다. 모든 유형을 원하면 점점 더 부울해야합니다 : 부울, null. 그리고 배열과 객체는 더 많은 작업이 필요합니다. 표준 정규식에서는 깊이 제한 만 가능합니다.
Brendan OConnor

9
1. jq .name명령 줄에서 작동하며 "스크립트를 작성하기 위해 편집기 열기"가 필요하지 않습니다. 2. 정규 표현식이 얼마나 빨리 잘못된 결과를 낼 수 있는지는 중요하지 않습니다
jfs

6
값만 원하면 그냥 엉망으로 만들 수 있습니다. | grep -Po '"text":.*?[^\\]",'|awk -F':' '{print $2}'
JeffCharter

34
OSX에서 -P옵션이 누락 된 것 같습니다 . 나는 OSX 10.11.5 테스트하고 grep --version있었다 grep (BSD grep) 2.5.1-FreeBSD. OSX에서 "확장 정규식"옵션을 사용하여 작업했습니다. 위의 명령은입니다 grep -Eo '"text":.*?[^\\]",' tweets.json.
Jens

174

여기에있는 몇 가지 권장 사항 (주석에서 언급)이 Python의 사용을 제안했기 때문에 예제를 찾지 못하는 것에 실망했습니다.

따라서 일부 JSON 데이터에서 단일 값을 얻는 하나의 라이너가 있습니다. 데이터를 (어딘가에서) 파이핑한다고 가정하므로 스크립팅 컨텍스트에서 유용해야합니다.

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

bash 함수를 사용하기 위해 아래의 답변을 향상 시켰습니다. curl 'some_api'| getJsonVal '키'
조 Heyming

pythonpy( github.com/russell91/pythonpypython -cpip와 함께 설치해야하지만 json을 파이프로 연결해야하지만 거의 항상 더 나은 대안 입니다. py --ji -x 'x[0]["hostname"]'내장 json_input 지원을 사용하지 않으려면 여전히 얻을 수 있습니다 자동으로 그 수입py 'json.loads(sys.stdin)[0]["hostname"]'
RussellStewart

2
감사! 더 빠르고 더러운 JSON 구문 분석을 위해 bash 함수로 래핑했습니다. jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); print($1)"; }그래서 다음 curl ...... | jsonq 'json.dumps([key["token"] for key in obj], indent=2)'과 같이 쓸 수 있습니다 : & 비슷한 무서운 것들 ... Btw, obj[0]불필요 한 것처럼 보입니다 obj. 기본 경우에는 정상적으로 작동 하는 것처럼 보입니다 (?).
akavel

감사. 나는이 존중 JSON을 인쇄보다 조금 더 좋게 만들었습니다.jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); sys.stdout.write(json.dumps($1))"; }
Adam K Dean

4
obj[0]구문 분석 할 때 오류가 발생합니다 { "port":5555 }. 제거 후 잘 작동합니다 [0].
CyberEd

134

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

37
OP가 요구할 때 특정 키를 어떻게 추출 하시겠습니까?
juan

2
지금까지 가장 좋은 대답은 대부분의 배포판에 다른 것을 설치할 필요가 없으며 가능하다는 것입니다 | grep field. 감사!
Andrea Richiardi

7
내가 실수하지 않으면이 형식은 JSON 형식입니다. 호출자가 xpath 솔루션이나 "JSON Pointer"에 기반한 것과 같이 출력에서 ​​특정 필드를 선택할 수 없습니다.
Cheeso

4
나는 단지 키 값 쌍으로 끝나지 만 그 자체로는 가치가 없습니다.
christopher

1
jq파이썬이 설치되어있는 동안 일반적으로 설치되지 않습니다. 또한 일단 파이썬으로 들어가면 전체를 분석하고 파싱 할 수도 있습니다import json...
CpILL

125

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

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

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

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


27
기록적인면 jq에서 놀라운 도구입니다.
hoss

2
동의했다. 나는 그것을 사용하지 않았기 때문에 허용 된 답변에서 jsawk와 비교할 수 없지만 로컬 실험 (도구 설치가 허용되는 곳)에서는 jq를 강력히 권장합니다. 다음은 배열의 각 요소를 사용하고 선택한 데이터로 새 JSON 객체를 합성하는 좀 더 광범위한 예입니다. curl -s https://api.example.com/jobs | jq '.jobs[] | {id, o: .owner.username, dateCreated, s: .status.state}'
jbyler

2
이거 너무 좋아. 매우 가볍고 평범한 오래된 C 언어이므로 거의 모든 곳에서 컴파일 할 수 있습니다.
Benmj

1
가장 실용적인 방법 : 써드 파티 라이브러리가 필요하지 않고 (jsawk에는 필요함) 설치하기 쉽습니다 (OSX : brew install jq)
lauhub December

1
이것은 내 유스 케이스에 가장 실용적이고 쉽게 구현되는 답변입니다. 우분투 (14.04) 시스템의 경우 간단한 apt-get install jq가 도구를 내 시스템에 추가했습니다. AWS CLI 응답의 JSON 출력을 jq로 파이핑하고 응답에 중첩 된 특정 키로 값을 추출하는 것이 좋습니다.
Brandon K

105

Node.js 사용

시스템에 설치되어 있으면 -pprint 를 사용하고 -e스크립트 플래그를 평가 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

1
감사! 하지만 제 경우에는 -e 플래그로만 작동합니다.node -p -e 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
Rnd_d

33
파이프! curl -s https://api.github.com/users/trevorsenior | node -pe "JSON.parse(require('fs').readFileSync('/dev/stdin').toString()).name"
nicerobot

4
이것은 내가 가장 좋아하는 솔루션입니다. 언어 (Javascript)를 사용하여 자연스런 데이터 구조 (JSON)를 구문 분석하십시오. 가장 정확한 것 같습니다 . 또한-노드는 이미 시스템에서 사용 가능할 수 있으며 jq의 이진 파일을 사용하지 않아도됩니다 (다른 올바른 선택으로 보입니다 ).
Eliran Malka

이것은 bash 스크립트 함수입니다. # jsonv는 특정 속성에 대한 json 객체 값을 가져옵니다. # 첫 번째 매개 변수는 json 문서입니다. # 두 번째 매개 변수는 값을 반환해야하는 속성입니다. get_json_attribute_value () {node -pe 'JSON.parse (process. argv [1]) [process.argv [2]] ' "$ 1" "$ 2"}
Youness

6
다음은 Node.js 10에서 작동합니다.cat package.json | node -pe 'JSON.parse(fs.readFileSync(0)).version'
Ilya Boyandin

100

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

이 같은:

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

6
좋은 반응을 보인 것에 대해 용서해주십시오 ... : 더 열심히 노력하겠습니다. Partisanship에는 awk 스크립트를 작성하는 것 이상이 필요합니다!
martinr

9
해당 oneliner 솔루션에서 obj 변수를 사용하는 이유는 무엇입니까? 그것은 쓸모없고 어쨌든 저장되지 않습니까? 다음 json.load(sys.stdin)['"key']"과 같은 예제를 사용하여 덜 쓰십시오 curl -sL httpbin.org/ip | python -c "import json,sys; print json.load(sys.stdin)['origin']".
m3nda

65

당신은 발로 자신을 쏘는 방법을 물었고 나는 탄약을 제공하기 위해 여기 있습니다.

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'

다른 사람들이 충분한 경보를 울렸다 고 생각합니다. 구급차를 부르기 위해 휴대 전화로 대기하겠습니다. 준비되면 발사하십시오.



3
나는 모든 답변을 읽었 으며이 답변은 추가 종속성없이 완벽하게 작동합니다. +1
eth0

그것이 내가 찾던 것입니다. 따옴표를 제거하는 유일한 수정-제공된 sed 명령이 작동하지 않았습니다. 대신 sed 's / "// g'를 사용했습니다
AlexG

44

파이썬에서 배쉬 사용하기

.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"
}

bash 기능이없는 1 개의 라이너 :curl http://foo | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["environment"][0]["name"]'
Cheeso

1
sys.stdout.write()파이썬 2와 3 모두에서 작동하기를 원한다면
Per Johansson

system.stdout.write (obj $ 1)로 변경해야한다고 생각합니다. 그렇게하면 말할 수 있습니다 : @Cheeso의 예와 같은 getJsonVal "[ 'environment'] [ 'name']"
Joe Heyming

1
이 경우 @Narek, 그것과 같을 것이다 : 기능getJsonVal() { py -x "json.dumps(json.loads(x)$1, sort_keys=True, indent=4)"; }
조 Heyming에게

30

틱틱 은 bash로 작성된 JSON 파서입니다 (<250 줄의 코드)

여기에 그의 기사에서 저자의 SNIPPIT의 배쉬는 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

2
여기서 유일하게 강력한 순수 bash 답변으로 더 많은 투표를 할 가치가 있습니다.
Ed Randall

이 사람들 변수를 json 문자열로 다시 인쇄하는 방법이 있습니까? 그것은 매우 유용 할 것입니다
Thomas Fournet

1
마지막으로 파이썬이나 다른 끔찍한 방법을 권장하지 않는 대답 ... 감사합니다!
아키토

21

PHP CLI로 JSON 파싱

논란의 여지가 있지만 우선 순위가 지배적이기 때문에이 질문은 신뢰할 수 있고 충실한 PHP에 대한 언급 없이는 불완전한 상태로 남아 있습니다.

동일한 예제 JSON을 사용하지만 변수를 할당하여 모호함을 줄입니다.

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

이제 file_get_contentsphp : // stdin 스트림 래퍼를 사용 하여 PHP를 개선하십시오 .

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

조이!


$argn대신 사용할 수도 있습니다fgets(STDIN)
IcanDivideBy0

죄송 $argn합니다. -E 또는 -R 플래그와 함께 작동하며 JSON 컨텐츠가 한 줄에있는 경우에만 해당됩니다.
IcanDivideBy0

21

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

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

대단해. 그러나 JSON 문자열은 두 개 이상의 전자 메일 키, 파서가 출력 john@doe.com ""john@doe.com 포함되어있는 경우
rtc11

jean-pierre@email.com과 같은 이메일에 대시가 있으면 작동하지 않습니다.
alexmngn

13

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

3
이것은 내가 가장 좋아하는;) BTW 라이브러리를 요구하기 위해 루비 -rjson으로 짧게 할 수있다
lucapette

;루비 에서는 최종 결과 가 필요하지 않습니다 (일반적으로 별도의 행에있는 명령문을 단일 행으로 연결하는 데에만 사용됨).
잭 모리스

11

불행히도 사용하는 최상위 투표 답변 은 내 시나리오에서 작동하지 않는 전체 일치를 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

실제로 JSON 사전에서 요소의 순서를 수는 없습니다 . 그것들은 정의상 비 순차적입니다. 이것이 바로 JSON 파서를 롤링하는 것이 근본적인 이유 중 하나입니다.
tripleee

10

누군가가 중첩 구조가 필요없는 간단한 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

페레이라 대령이 함수로 중첩 된 속성 값을 추출 할 수 있습니까?
vsbehere

8

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

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

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


문자열 연결을 사용하여 코드로 구문 분석 된 문자열로 값을 대체하면 임의의 node.js 코드가 실행될 수 있습니다. 즉, 인터넷에서 가져온 임의의 컨텐츠와 함께 사용하는 것은 매우 안전하지 않습니다. JavaScript로 JSON을 구문 분석하는 안전하고 최선의 방법은 단순히 평가하는 것이 아닙니다.
찰스 더피

@CharlesDuffy 나는 확실하지 않지만 JSON.parse 호출은 require()실제로 외부 코드를 실행할 수 있으므로 JSON.parse 호출이 더 안전해야합니다 .
Alexander Mills

파서를 우회하는 방식으로 문자열이 실제로 JSON 런타임에 주입되는 경우에만 해당됩니다. 여기서 코드가 안정적으로 수행되는 것을 보지 못했습니다. 환경 변수에서 가져 와서 전달하십시오. JSON.parse()예, 확실합니다. 그러나 여기서 JSON 런타임은 (신뢰할 수있는) 코드로 대역 내 (신뢰할 수없는) 콘텐츠를 수신 합니다.
Charles Duffy

... 유사하게 코드에서 파일의 JSON을 문자열로 읽고 해당 문자열 을에 전달 JSON.parse()하면 안전하지만 여기에서도 발생하지 않습니다.
Charles Duffy

1
... 아, 도대체 바로 "방법"으로 들어갈 수도 있습니다. 문제는 전달하려는 쉘 변수를 JSON.parse()코드로 대체 한다는 입니다. 당신이있어 가정 인용을 종료하고, 인용 부호로 둘러싸이지 않은 상황을 입력 할 수 있습니다 따라서 리터럴 역 따옴표 퍼팅 내용이 그대로 유지됩니다 만, 리터럴 역 따옴표는 파일 내용에 존재하는 (따라서 변수) 할 수 있기 때문에 즉, 완전히 안전하지 않은 가정, 그리고 어디에 값은 코드로 실행됩니다.
Charles Duffy

7

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

}

분명히 유닉스에서 Windows 셸을 사용하는 것은 다소 희생적이지만 Powershell은 실제로 몇 가지 장점이 있으며 JSON과 XML을 파싱하는 것이 그 중 일부입니다. 크로스 플랫폼 버전의 GitHub 페이지 https://github.com/PowerShell/PowerShell


툴을 오픈 소스하고 오픈 소스 외부 툴을 통합하는 새로운 Microsoft 전략을 홍보하고 있기 때문에 공감했습니다. 우리 세상에 좋은 일입니다.
Alex

나는 PowerShell을 싫어했지만 이전에는 객체 처리가 훌륭하기 때문에 JSON 처리를 인정해야합니다.
MartinThé

6

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'

1
또는 요즘 더 간단합니다 : xidel -s https://api.github.com/users/lambda -e 'name'(또는 -e '$json/name', 또는 -e '($json).name').
레이노

6

나는 여기에 어떤 대답도 사용할 수 없습니다. 사용 가능한 jq, 쉘 배열, 선언 없음, grep -P, lookbehind 및 lookahead, Python, Perl, Ruby, No-Bash조차도 없습니다. 남은 대답은 단순히 잘 작동하지 않습니다. JavaScript는 친숙하게 들리지만 주석은 Nescaffe라고 말합니다.

그러나 모뎀의 json 형식 응답에서 많은 변수를 얻는 것이 매우 중요합니다. 내 라우터에서 BusyBox를 매우 잘린 채로 sh에서하고 있습니다! awk 만 사용하는 데 아무런 문제가 없습니다. 구분 기호를 설정하고 데이터를 읽으십시오. 단일 변수의 경우 그게 전부입니다!

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

배열이 없다는 것을 기억하십니까? 쉘 스크립트에서 필요한 11 개의 변수에 awk 구문 분석 된 데이터를 할당해야했습니다. 내가 어디를 보더라도 그것은 불가능한 사명이라고 말했다. 그것도 문제 없습니다.

내 솔루션은 간단합니다. 이 코드는 다음과 같습니다 : 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 초


5

당신은 이런 식으로 시도 할 수 있습니다-

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

5

당신은 사용할 수 있습니다 jshon:

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

이 사이트는 다음과 같이 말합니다. "두 배, 메모리의 1/6."그리고 "Jshon은 JSON을 파싱하고 읽고 생성합니다. 쉘 내에서 가능한 한 사용 가능하도록 설계되었으며 깨지기 쉬운 임시 파서들을 대체합니다. grep / sed / awk와 펄 / 파이썬으로 만든 헤비급 1 줄 파서. "
Roger

이것은 배쉬에서 JSON을 구문 분석을 위해 권장되는 솔루션으로 나열
qodeninja

결과 주변의 따옴표를 제거하는 가장 쉬운 방법은 무엇입니까?
gMale

4

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

4

더 복잡한 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로 코드를 래핑해야합니다.


아름다운 관용구. 난 파이썬 몰라,하지만이 강력한 솔루션처럼 보인다
스리 Sarnobat에게

내가 설치 약간의 문제가 있고 있었다 jsonpath그래서 설치 jsonpath_rw1) 대신에, 그래서 여기를 작업 위의 경우 시도 할 수 있습니다 비슷한되지 않습니다이다 /usr/bin/python -m pip install jsonpath-rw2) cat ~/trash/file.json | /usr/bin/python -c "from jsonpath_rw import jsonpath, parse; import sys,json; jsonpath_expr = parse('store.book[0]'); out = [match.value for match in jsonpath_expr.find(json.load(sys.stdin))]; print out;"(I 여러 비단뱀 몇 가지 문제가 있었기 때문에 내가 파이썬 바이너리의 전체 경로를 사용 설치).
Sridhar Sarnobat

4

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

중첩 배열이 있으면이 출력이 훨씬 좋아 보입니다 ...

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


4

매우 간단하지만 강력한도있다 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


7
자신의 창작물을 홍보하는 경우 명시 적으로 표현해야합니다. 스패머가되지 않는 방법을
tripleee

4

이것은 또 다른입니다 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
  }
}

다음 예제에서 나는 자체 구현 jqunquote활용을 만들었습니다 python. 파이썬 객체를 json파이썬 사전으로 가져 오면 파이썬 구문을 사용하여 사전을 탐색 할 수 있습니다. 위를 탐색하는 구문은 다음과 같습니다.

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

bash에서 magic을 사용 data하면 파이썬 텍스트를 생략 하고 데이터 오른쪽에 제공합니다.

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

매개 변수가 없으면 jq JSON 프리 테이너로 작동합니다. 매개 변수를 사용하면 파이썬 구문을 사용하여 사전 및 배열 요소 탐색을 포함하여 사전에서 원하는 것을 추출 할 수 있습니다.

위의 내용을 보여주는 실제 예제는 다음과 같습니다.

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 )"
}

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

3

다음과 같이 특정 값에 대한 json 응답을 "구문 분석"했습니다.

curl $url | grep $var | awk '{print $2}' | sed s/\"//g 

분명히 $ url은 트위터 URL이고 $ var는 "text"가되어 해당 var에 대한 응답을 얻습니다.

실제로, 내가 OP를하고있는 유일한 것은 그가 찾고있는 특정 변수가있는 줄에 대한 grep이라고 생각합니다. Awk는 라인의 두 번째 항목을 잡고 sed를 사용하여 따옴표를 제거합니다.

나보다 똑똑한 사람은 아마도 전체적인 생각을 awk 나 grep으로 할 수있을 것입니다.

이제 sed로 모든 것을 할 수 있습니다.

curl $url | sed '/text/!d' | sed s/\"text\"://g | sed s/\"//g | sed s/\ //g

따라서, 어색함, grep 없음 ... 나는 왜 내가 전에 그런 생각을하지 않았는지 모르겠다. 흠 ...


실제로, sed로 할 수 있습니다
tonybaldwin

1
grep | awk | sedsed | sed | sed파이프 라인 낭비 반 패턴입니다. 마지막 예제는 쉽게 다시 쓸 수 curl "$url" | sed '/text/!d;s/\"text\"://g;s/\"//g;s/\ //g'있지만 다른 사람들이 지적했듯이 오류가 발생하기 쉽고 취 성적 인 접근 방식이므로 처음에는 권장하지 않아야합니다.
tripleee

grep -oPz 'name \ ": \". *? \ "'curloutput | sed 's / name \": / \ n / g'를
사용해야했습니다.

3

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

3

파이썬을 사용하는 2 라이너. 단일 .sh 파일을 작성하고 다른 .py 파일에 의존하지 않으려는 경우 특히 효과적입니다. 또한 파이프 사용을 활용합니다 |. echo "{\"field\": \"value\"}"stdout에 json을 인쇄하는 것으로 대체 할 수 있습니다.

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

문제는 파이썬 솔루션을 찾고 있지 않았습니다. 의견도 참조하십시오.
Andrew Barber

3

이것은 pythonpy 의 좋은 유스 케이스입니다 .

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

더 짧은 파이썬 -c 모듈 여기 :) 좋습니다.
m3nda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.