Phân tích cú pháp JSON bằng các công cụ Unix


879

Tôi đang cố phân tích JSON được trả về từ một yêu cầu curl, như vậy:

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

Ở trên, chia JSON thành các trường, ví dụ:

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

Làm cách nào để in một trường cụ thể (ký hiệu là -v k=text)?


5
Erm đó không phải là tốt json phân tích cú pháp btw ... còn các ký tự thoát trong chuỗi ... vv Có câu trả lời python cho điều này trên SO (một câu trả lời perl thậm chí ...)?
martinr

51
Bất cứ khi nào ai đó nói "vấn đề X có thể dễ dàng được giải quyết bằng ngôn ngữ Y khác", đó là mã cho "hộp công cụ của tôi chỉ có một tảng đá để lái đinh ... tại sao phải bận tâm với bất cứ điều gì khác?"
BryanH

22
@BryanH: ngoại trừ đôi khi ngôn ngữ Y có thể được trang bị nhiều hơn để giải quyết vấn đề cụ thể X bất kể có bao nhiêu ngôn ngữ mà người đề xuất Y biết.
jfs

15
Kinda muộn, nhưng ở đây nó đi. grep -Po '"'"version"'"\s*:\s*"\K([^"]*)' package.json. Điều này giải quyết công việc dễ dàng & chỉ với grep và hoạt động hoàn hảo cho các JSON đơn giản. Đối với các JSON phức tạp, bạn nên sử dụng một trình phân tích cú pháp thích hợp.
diosney

2
@auser, bạn có ổn không khi chỉnh sửa thay đổi "với sed và awk" thành "với các công cụ UNIX" trong tiêu đề?
Charles Duffy

Câu trả lời:


1127

Có một số công cụ được thiết kế dành riêng cho mục đích thao tác JSON từ dòng lệnh và sẽ dễ dàng và đáng tin cậy hơn nhiều so với thực hiện với Awk, chẳng hạn như jq:

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

Bạn cũng có thể làm điều này với các công cụ có khả năng đã được cài đặt trên hệ thống của bạn, như Python sử dụng jsonmô-đun , và do đó tránh mọi phụ thuộc bổ sung, trong khi vẫn có lợi ích của trình phân tích cú pháp JSON thích hợp. Giả định sau đây bạn muốn sử dụng UTF-8, mà JSON gốc phải được mã hóa và là thứ mà hầu hết các thiết bị đầu cuối hiện đại cũng sử dụng:

Con trăn 3:

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

Con trăn 2:

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

Ghi chú lịch sử

Câu trả lời này ban đầu khuyến nghị jsawk , vẫn nên hoạt động, nhưng hơi khó sử dụng hơn một chút jqvà phụ thuộc vào trình thông dịch JavaScript độc lập đang được cài đặt ít phổ biến hơn trình thông dịch Python, vì vậy các câu trả lời trên có thể thích hợp hơn:

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

Câu trả lời này ban đầu cũng sử dụng API Twitter từ câu hỏi, nhưng API đó không còn hoạt động nữa, khiến việc sao chép các ví dụ để kiểm tra trở nên khó khăn và API Twitter mới yêu cầu các khóa API, vì vậy tôi đã chuyển sang sử dụng API GitHub. có thể được sử dụng dễ dàng mà không cần khóa API. Câu trả lời đầu tiên cho câu hỏi ban đầu sẽ là:

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

7
@thrau +1. jq nó có sẵn trong kho lưu trữ và siêu dễ sử dụng vì vậy nó tốt hơn nhiều so với jsawk. Tôi đã thử nghiệm cả hai trong vài phút, jq đã thắng trận chiến này
Szymon Sadło

1
Lưu ý rằng trong Python 2, nếu bạn đang dẫn đầu ra sang một lệnh khác thì printcâu lệnh sẽ luôn mã hóa thành ASCII vì bạn đang sử dụng Python trong một đường ống. Chèn PYTHONIOENCODING=<desired codec>vào lệnh để đặt mã hóa đầu ra khác, phù hợp với thiết bị đầu cuối của bạn. Trong Python 3, mặc định là UTF-8 trong trường hợp này (sử dụng print() hàm ).
Martijn Pieters

1
Cài đặt jq trên OSX với cài đặt brew jq
Andy Fraley

1
curl -slà tương đương với curl --silent, trong khi đó jq -rcó nghĩa jq --raw-outputlà không có dấu ngoặc kép.
Serge Stroobandt

python -c "nhập yêu cầu; r = request.get (' api.github.com/users/lambda');print r.json () [' name '];" . Đơn giản nhất!
NotTooTechy

277

Để nhanh chóng trích xuất các giá trị cho một khóa cụ thể, cá nhân tôi muốn sử dụng "grep -o", chỉ trả về kết quả khớp của regex. Ví dụ: để lấy trường "văn bản" từ các tweet, đại loại như:

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

Regex này mạnh hơn bạn nghĩ; ví dụ, nó xử lý tốt với các chuỗi có dấu phẩy nhúng và thoát dấu ngoặc kép bên trong chúng. Tôi nghĩ rằng với một chút công việc hơn, bạn có thể tạo ra một thứ thực sự được đảm bảo để trích xuất giá trị, nếu đó là nguyên tử. (Nếu nó có lồng nhau, thì dĩ nhiên một regex không thể làm điều đó.)

Và để làm sạch hơn nữa (mặc dù vẫn giữ thoát gốc của chuỗi), bạn có thể sử dụng một cái gì đó như : | perl -pe 's/"text"://; s/^"//; s/",$//'. (Tôi đã làm điều này cho phân tích này .)

Đối với tất cả những người ghét yêu cầu bạn nên sử dụng trình phân tích cú pháp JSON thực - vâng, đó là điều cần thiết cho tính chính xác, nhưng

  1. Để thực hiện phân tích thực sự nhanh chóng, như đếm các giá trị để kiểm tra lỗi làm sạch dữ liệu hoặc cảm nhận chung về dữ liệu, đập ra một cái gì đó trên dòng lệnh sẽ nhanh hơn. Mở một trình soạn thảo để viết một kịch bản là mất tập trung.
  2. grep -olà các đơn đặt hàng có cường độ nhanh hơn jsonthư viện chuẩn Python , ít nhất là khi thực hiện điều này cho các tweet (mỗi ~ 2 KB). Tôi không chắc liệu đây có phải là vì jsonchậm không (đôi khi tôi nên so sánh với yajl); nhưng về nguyên tắc, một regex nên nhanh hơn vì nó là trạng thái hữu hạn và tối ưu hơn nhiều, thay vì một trình phân tích cú pháp phải hỗ trợ đệ quy, và trong trường hợp này, dành nhiều cây xây dựng CPU cho các cấu trúc mà bạn không quan tâm. (Nếu ai đó đã viết một bộ chuyển đổi trạng thái hữu hạn đã thực hiện phân tích cú pháp JSON đúng (giới hạn độ sâu), điều đó thật tuyệt vời! Trong khi đó, chúng ta có "grep -o".)

Để viết mã có thể duy trì, tôi luôn sử dụng một thư viện phân tích cú pháp thực sự. Tôi chưa thử jsawk , nhưng nếu nó hoạt động tốt, điều đó sẽ giải quyết điểm # 1.

Một giải pháp cuối cùng, lập dị hơn: Tôi đã viết một tập lệnh sử dụng Python jsonvà trích xuất các khóa bạn muốn, thành các cột được phân tách bằng tab; sau đó tôi dẫn qua một trình bao bọc xung quanh awkcho phép truy cập được đặt tên vào các cột. Ở đây: các tập lệnh json2tsv và tsvawk . Vì vậy, với ví dụ này, nó sẽ là:

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

Cách tiếp cận này không giải quyết được vấn đề # 2, kém hiệu quả hơn so với một tập lệnh Python đơn lẻ và nó hơi dễ vỡ: nó buộc phải chuẩn hóa các dòng mới và các tab trong các giá trị chuỗi, để chơi tốt với chế độ xem trường / phân tách bản ghi của awk về thế giới. Nhưng nó không cho phép bạn ở trên dòng lệnh, với độ chính xác cao hơn grep -o.


11
Bạn đã quên về các giá trị số nguyên. grep -Po '"text":(\d*?,|.*?[^\\]",)'
Robert

3
Robert: Phải, regex của tôi chỉ được viết cho các giá trị chuỗi cho trường đó. Số nguyên có thể được thêm vào như bạn nói. Nếu bạn muốn tất cả các loại, bạn phải làm nhiều hơn và nhiều hơn nữa: booleans, null. Và mảng và đối tượng đòi hỏi nhiều công việc hơn; chỉ giới hạn độ sâu là có thể, theo các tiêu chuẩn.
Brendan OConnor

9
1. jq .namehoạt động trên dòng lệnh và nó không yêu cầu "mở trình soạn thảo để viết tập lệnh". 2. Không quan trọng là regex của bạn có thể tạo ra kết quả sai nhanh đến mức nào
jfs

6
và nếu bạn chỉ muốn các giá trị bạn có thể ném awk vào nó. | grep -Po '"text":.*?[^\\]",'|awk -F':' '{print $2}'
JeffCharter

34
Có vẻ như trên OSX, -Ptùy chọn bị thiếu. Tôi đã thử nghiệm trên OSX 10.11.5 và grep --versionđược grep (BSD grep) 2.5.1-FreeBSD. Tôi đã làm cho nó hoạt động với tùy chọn "regex mở rộng" trên OSX. Lệnh từ trên sẽ là grep -Eo '"text":.*?[^\\]",' tweets.json.
Jens

174

Trên cơ sở một số khuyến nghị ở đây (đặc biệt trong các bình luận) đề xuất sử dụng Python, tôi đã thất vọng khi không tìm thấy một ví dụ.

Vì vậy, đây là một lớp lót để có được một giá trị từ một số dữ liệu JSON. Nó giả định rằng bạn đang dẫn dữ liệu vào (từ một nơi nào đó) và do đó sẽ hữu ích trong bối cảnh kịch bản.

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

Tôi đã nâng cao câu trả lời dưới đây để sử dụng hàm bash: curl 'some_api' | getJsonVal 'key'
Joe Heyming

pythonpy( github.com/russell91/pythonpy hầu như luôn là lựa chọn thay thế tốt hơn python -c, mặc dù nó phải được cài đặt bằng pip. Chỉ cần đặt json vào py --ji -x 'x[0]["hostname"]'. Nếu bạn không muốn sử dụng hỗ trợ json_input tích hợp, bạn vẫn có thể nhận được nhập tự động dưới dạngpy 'json.loads(sys.stdin)[0]["hostname"]'
RussellStewart

2
Cảm ơn! Để phân tích cú pháp JSON nhanh và bẩn hơn, tôi đã gói nó vào hàm bash: jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); print($1)"; }để tôi có thể viết: curl ...... | jsonq 'json.dumps([key["token"] for key in obj], indent=2)'& nhiều nội dung đáng sợ tương tự ... Btw, obj[0]dường như không cần thiết, có vẻ như chỉ objhoạt động tốt trong các trường hợp mặc định (?).
akavel

Cảm ơn. Tôi đã làm cho sự tôn trọng này tốt hơn một chút so với in ấn:jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); sys.stdout.write(json.dumps($1))"; }
Adam K Dean

4
obj[0]gây ra lỗi khi phân tích cú pháp { "port":5555 }. Hoạt động tốt sau khi loại bỏ [0].
CyberEd

134

Theo sự dẫn dắt của MartinR và Boecko:

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

Điều đó sẽ cung cấp cho bạn một đầu ra cực kỳ thân thiện grep. Rât thuận tiện:

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

37
Làm thế nào bạn sẽ trích xuất một khóa cụ thể, như OP đang yêu cầu?
juan

2
Câu trả lời tốt nhất cho đến nay imho, không cần phải cài đặt bất cứ điều gì khác trên hầu hết các bản phát hành và bạn có thể | grep field. Cảm ơn!
Andrea Richiardi

7
Tất cả điều này là định dạng JSON, nếu tôi không nhầm. Nó không cho phép người gọi chọn một trường cụ thể từ đầu ra, như một giải pháp xpath hoặc một cái gì đó dựa trên "Con trỏ JSON".
Cheeso

4
Tôi chỉ kết thúc với một cặp giá trị chính, nhưng không phải là giá trị trong chính nó.
christopher

1
jqthường không được cài đặt trong khi python là. Ngoài ra, một khi bạn ở trong Python, bạn cũng có thể đi theo toàn bộ con đường và phân tích nó vớiimport json...
CpILL

125

Bạn chỉ có thể tải xuống jqnhị phân cho nền tảng của mình và chạy ( chmod +x jq):

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

Nó trích xuất "name"thuộc tính từ đối tượng json.

jqTrang chủ cho biết nó giống như sedđối với dữ liệu JSON.


27
Chỉ cần cho hồ sơ, jqlà một công cụ tuyệt vời.
hoss

2
Đã đồng ý. Tôi không thể so sánh với jsawk từ câu trả lời được chấp nhận, vì tôi chưa sử dụng nó, nhưng đối với thử nghiệm cục bộ (nơi cài đặt một công cụ có thể chấp nhận được) tôi rất khuyến nghị jq. Đây là một ví dụ rộng hơn một chút, lấy từng phần tử của một mảng và tổng hợp một đối tượng JSON mới với dữ liệu đã chọn: curl -s https://api.example.com/jobs | jq '.jobs[] | {id, o: .owner.username, dateCreated, s: .status.state}'
jbyler

2
Thích cái này. Trọng lượng rất nhẹ, và vì nó ở C cũ, nên nó có thể được biên dịch ở bất cứ đâu.
Benmj

1
Cách thực tế nhất: nó không cần thư viện của bên thứ ba (trong khi jsawk không) và rất dễ cài đặt (OSX: brew install jq)
lauhub

1
Đây là câu trả lời thiết thực và dễ thực hiện nhất cho trường hợp sử dụng của tôi. Đối với hệ thống Ubuntu (14.04), jq cài đặt apt-get đơn giản đã thêm công cụ vào hệ thống của tôi. Tôi đang chuyển đầu ra JSON từ các phản hồi AWS CLI vào jq và nó hoạt động rất tốt để trích xuất các giá trị cho các khóa nhất định được lồng trong phản hồi.
Brandon K

105

Sử dụng Node.js

Nếu hệ thống có đã cài đặt, có thể sử dụng -pin và in các -ecờ script JSON.parseđể lấy ra bất kỳ giá trị nào cần thiết.

Một ví dụ đơn giản sử dụng chuỗi JSON { "foo": "bar" }và lấy ra giá trị của "foo":

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

Vì chúng tôi có quyền truy cập catvà các tiện ích khác, chúng tôi có thể sử dụng điều này cho các tệp:

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

Hoặc bất kỳ định dạng nào khác, chẳng hạn như một URL có chứa JSON:

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

1
cảm ơn! nhưng trong trường hợp của tôi, nó chỉ hoạt động với cờ -enode -p -e 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
Rnd_d

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

4
đây là giải pháp yêu thích của tôi; sử dụng một ngôn ngữ (javascript) để phân tích cấu trúc dữ liệu tự nhiên đối với nó (JSON). Dường như hầu hết đúng . Ngoài ra - nút có thể đã có sẵn trên hệ thống và bạn sẽ không phải xử lý các tệp nhị phân của jq (trông giống như một lựa chọn chính xác khác).
Eliran Malka

Đây là hàm bash script: # jsonv lấy giá trị đối tượng json cho một thuộc tính cụ thể # tham số đầu tiên là tài liệu json # tham số thứ hai là thuộc tính cần trả về giá trị get_json_attribution_value () {node -pe 'JSON.parse (process. argv [1]) [process.argv [2]] '"$ 1" "$ 2"}
Youness

6
Sau đây hoạt động với Node.js 10:cat package.json | node -pe 'JSON.parse(fs.readFileSync(0)).version'
Ilya Boyandin

100

Sử dụng hỗ trợ JSON của Python thay vì sử dụng awk!

Một cái gì đó như thế này:

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

6
Xin lỗi vì đã cố gắng đưa ra một phản hồi tốt ...: Tôi sẽ cố gắng hơn nữa. Hợp tác đòi hỏi nhiều hơn là viết một kịch bản awk để rũ bỏ nó!
martinr

9
Tại sao bạn sử dụng biến obj trong giải pháp oneliner đó?. Nó vô dụng và dù sao cũng không được lưu trữ? Bạn viết ít sử dụng json.load(sys.stdin)['"key']"như ví dụ như : curl -sL httpbin.org/ip | python -c "import json,sys; print json.load(sys.stdin)['origin']".
m3nda

65

Bạn đã hỏi làm thế nào để tự bắn vào chân mình và tôi ở đây để cung cấp đạn:

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

Bạn có thể sử dụng tr -d '{}'thay vì sed. Nhưng bỏ chúng hoàn toàn dường như cũng có hiệu quả mong muốn.

Nếu bạn muốn loại bỏ các trích dẫn bên ngoài, hãy dẫn đến kết quả của phần trên sed 's/\(^"\|"$\)//g'

Tôi nghĩ rằng những người khác đã nghe đủ báo động. Tôi sẽ đứng bên cạnh với một chiếc điện thoại di động để gọi xe cứu thương. Sẵn sàng bắn.


10
Bằng cách này, sự điên rồ nói dối, hãy đọc điều này: stackoverflow.com/questions/1732348/ cấp
Tạm dừng cho đến khi có thông báo mới.

3
Tôi đã đọc tất cả các câu trả lời và câu trả lời này hoạt động hoàn hảo cho tôi mà không có bất kỳ sự phụ thuộc nào. +1
eth0

Đó là những gì tôi đang tìm kiếm. Điều chỉnh duy nhất - được cung cấp lệnh sed để xóa dấu ngoặc kép không hoạt động đối với tôi, tôi đã sử dụng sed 's / "// g' thay vào đó
AlexG

44

Sử dụng Bash với Python

Tạo hàm bash trong tệp .bash_rc của bạn

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

Sau đó

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

Đây là chức năng tương tự, nhưng với kiểm tra lỗi.

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

Trong đó $ # -ne 1 đảm bảo ít nhất 1 đầu vào và -t 0 đảm bảo bạn đang chuyển hướng từ một đường ống.

Điều thú vị về việc triển khai này là bạn có thể truy cập các giá trị json lồng nhau và nhận lại json! =)

Thí dụ:

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

Nếu bạn muốn thực sự lạ mắt, bạn có thể in dữ liệu:

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

Một lớp lót không có chức năng bash:curl http://foo | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["environment"][0]["name"]'
Cheeso

1
sys.stdout.write()nếu bạn muốn nó hoạt động với cả python 2 và 3.
Per Johansson

Tôi nghĩ rằng nó nên thay đổi thành system.stdout.write (obj $ 1). Bằng cách đó bạn có thể nói: getJsonVal "['môi trường'] ['name']", như ví dụ của
@Cheeso

1
@Narek Trong trường hợp đó, nó sẽ trông như thế này: chức nănggetJsonVal() { py -x "json.dumps(json.loads(x)$1, sort_keys=True, indent=4)"; }
Joe Heyming

30

TickTick là một trình phân tích cú pháp JSON được viết bằng bash (<250 dòng mã)

Đây là đoạn trích của tác giả từ bài viết của mình, Hãy tưởng tượng một thế giới nơi Bash hỗ trợ 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
Là câu trả lời thuần túy mạnh mẽ duy nhất ở đây, điều này xứng đáng nhận được nhiều sự ủng hộ hơn.
Ed Randall

Có cách nào để in biến người này thành chuỗi json nữa không? Điều đó sẽ vô cùng hữu ích
Thomas Fournet

1
Cuối cùng, một câu trả lời không khuyến nghị Python hoặc các phương pháp tàn bạo khác ... Cảm ơn bạn!
Akito

21

Phân tích cú pháp JSON bằng PHP CLI

Có thể cho là lạc đề nhưng từ trước đó, câu hỏi này vẫn chưa hoàn chỉnh mà không đề cập đến PHP đáng tin cậy và trung thành của chúng tôi, tôi có đúng không?

Sử dụng cùng một ví dụ JSON nhưng cho phép gán nó cho một biến để giảm độ mờ.

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

Bây giờ vì sự tốt lành của PHP, sử dụng file_get_contents và trình bao bọc luồng php: // stdin .

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

hoặc như được chỉ ra bằng cách sử dụng fgets và luồng đã được mở tại CLI hằng STDIN .

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

Xin chào!


Bạn thậm chí có thể sử dụng $argnthay vìfgets(STDIN)
IcanDivideBy0

Rất tiếc, $argnhoạt động với cờ -E hoặc -R và chỉ khi nội dung JSON nằm trên một dòng ...
IcanDivideBy0

21

Phiên bản gốc Bash: Cũng hoạt động tốt với dấu gạch chéo ngược (\) và dấu ngoặc kép (")

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

Điều này thật tuyệt. Nhưng nếu chuỗi JSON chứa nhiều khóa email, trình phân tích cú pháp sẽ xuất ra john@doe.com "" john@doe.com
rtc11

Không hoạt động nếu có một dấu gạch ngang trong email như jean-pierre@email.com
alexmngn 15/03/19

13

Phiên bản sử dụng Ruby và http://flori.github.com/json/

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

hoặc chính xác hơn:

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

3
đây là sở thích của tôi;) BTW bạn có thể rút ngắn nó bằng ruby ​​-rjson để yêu cầu thư viện
lucapette

Lưu ý rằng trận chung kết ;không bắt buộc trong Ruby (nó chỉ được sử dụng để ghép các câu lệnh thường nằm trên các dòng riêng biệt thành một dòng).
Zack Morris

11

Thật không may, câu trả lời được bình chọn hàng đầu sử dụng greptrả về kết quả khớp hoàn toàn không hoạt động trong kịch bản của tôi, nhưng nếu bạn biết định dạng JSON sẽ không đổi, bạn có thể sử dụng lookbehindlookahead để trích xuất các giá trị mong muốn.

# 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

Bạn thực sự không bao giờ biết thứ tự của các phần tử trong từ điển JSON. Họ, theo định nghĩa, không có thứ tự. Đây chính xác là một trong những lý do cơ bản tại sao việc phân tích trình phân tích cú pháp JSON của riêng bạn là một cách tiếp cận cam chịu.
tripleee

10

Nếu ai đó chỉ muốn trích xuất các giá trị từ các đối tượng JSON đơn giản mà không cần các cấu trúc lồng nhau, có thể sử dụng các biểu thức thông thường mà không cần rời khỏi bash.

Đây là một hàm tôi đã xác định bằng cách sử dụng các biểu thức chính quy bash dựa trên tiêu chuẩn JSON :

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
}

Hãy cẩn thận: các đối tượng và mảng không được hỗ trợ dưới dạng giá trị, nhưng tất cả các loại giá trị khác được xác định trong tiêu chuẩn đều được hỗ trợ. Ngoài ra, một cặp sẽ được khớp với nhau cho dù tài liệu JSON có sâu đến đâu miễn là nó có cùng tên chính xác.

Sử dụng ví dụ của 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

Helder Pereira chúng ta có thể trích xuất các giá trị thuộc tính lồng nhau với hàm này không?
so với

8

Có một cách dễ dàng hơn để có được một tài sản từ một chuỗi json. Sử dụng một package.jsontệp làm ví dụ, hãy thử điều này:

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

Chúng tôi đang sử dụng process.envvì điều này đưa nội dung của tệp vào tệp node.js dưới dạng một chuỗi mà không có bất kỳ rủi ro nào về nội dung độc hại thoát khỏi trích dẫn của chúng và được phân tích cú pháp dưới dạng mã.


Sử dụng nối chuỗi để thay thế các giá trị thành một chuỗi được phân tích cú pháp dưới dạng mã cho phép mã node.js tùy ý được chạy, nghĩa là nó cực kỳ không an toàn khi sử dụng với nội dung ngẫu nhiên bạn đã tắt Internet. Có một lý do an toàn / cách thực hành tốt nhất để phân tích JSON trong JavaScript không chỉ đánh giá nó.
Charles Duffy

@CharlesDuffy không chắc chắn tôi làm theo nhưng cuộc gọi JSON.parse sẽ an toàn hơn, vì require()thực sự có thể chạy mã nước ngoài, JSON.parse không thể.
Alexander Mills

Điều đó đúng nếu và chỉ - nếu chuỗi của bạn thực sự được đưa vào thời gian chạy JSON theo cách để bỏ qua trình phân tích cú pháp. Tôi không thấy mã ở đây làm điều đó đáng tin cậy. Kéo nó từ một biến môi trường và chuyển nó đến JSON.parse()và có, bạn hoàn toàn an toàn ... nhưng ở đây, bộ thực thi JSON đang nhận nội dung (không đáng tin cậy) trong mã với mã (đáng tin cậy).
Charles Duffy

... Tương tự, nếu mã của bạn đọc JSON từ tệp dưới dạng chuỗi và chuyển chuỗi đó sang JSON.parse(), thì bạn cũng an toàn, nhưng điều đó cũng không xảy ra ở đây.
Charles Duffy

1
... À, chết tiệt, cũng có thể đi vào "làm thế nào" ngay lập tức. Vấn đề là ở đó bạn đang thay thế biến shell mà bạn dự định chuyển JSON.parse()sang mã . Bạn đang giả định rằng việc đặt backticks theo nghĩa đen sẽ giữ nội dung theo nghĩa đen, nhưng đó là một giả định hoàn toàn không an toàn, bởi vì backticks theo nghĩa đen có thể tồn tại trong nội dung tệp (và do đó là biến), do đó có thể chấm dứt trích dẫn và nhập vào một ngữ cảnh không được trích dẫn trong đó các giá trị được thực thi dưới dạng mã.
Charles Duffy

7

Bây giờ Powershell là nền tảng chéo, tôi nghĩ rằng tôi sẽ tìm đường ra khỏi đó, vì tôi thấy nó khá trực quan và cực kỳ đơn giản.

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

ConvertFrom-Json chuyển đổi JSON thành một đối tượng tùy chỉnh Powershell, do đó bạn có thể dễ dàng làm việc với các thuộc tính từ thời điểm đó trở đi. Nếu bạn chỉ muốn thuộc tính 'id' chẳng hạn, bạn chỉ cần làm điều này:

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

Nếu bạn muốn gọi toàn bộ từ Bash, thì bạn phải gọi nó như thế này:

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

Tất nhiên, có một cách Powershell thuần túy để làm điều đó mà không làm cong, đó sẽ là:

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

Cuối cùng, cũng có 'ConvertTo-Json' giúp chuyển đổi một đối tượng tùy chỉnh thành JSON dễ dàng. Đây là một ví dụ:

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

Điều này sẽ tạo ra JSON đẹp như thế này:

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

}

Phải thừa nhận rằng, việc sử dụng trình bao Windows trên Unix có phần hơi bất thường nhưng Powershell thực sự giỏi một số thứ và phân tích JSON và XML là một vài trong số đó. Đây là trang GitHub cho phiên bản đa nền tảng https://github.com/PowerShell/PowerShell


được khuyến khích bởi vì bạn đang quảng bá chiến lược mới của Microsoft cho các công cụ nguồn mở của họ và kết hợp các công cụ nước ngoài nguồn mở. Đó là một điều tốt cho thế giới của chúng ta.
Alex

Tôi đã từng không thích PowerShell, nhưng tôi phải thừa nhận việc xử lý JSON vì các đối tượng khá đẹp.
MartinThé

6

Ai đó cũng có tệp xml, có thể muốn xem Xidel của tôi . Nó là một JSONiq không phụ thuộc bộ xử lý . (tức là nó cũng hỗ trợ XQuery để xử lý xml hoặc json)

Ví dụ trong câu hỏi sẽ là:

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

Hoặc với cú pháp mở rộng không chuẩn của riêng tôi:

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

1
Hoặc đơn giản hơn hiện nay: xidel -s https://api.github.com/users/lambda -e 'name'(hoặc -e '$json/name', hoặc -e '($json).name').
Reino

6

Tôi không thể sử dụng bất kỳ câu trả lời ở đây. Không có jq, không có mảng shell, không khai báo, không grep -P, không lookbehind và lookahead, không Python, không Perl, không Ruby, không - thậm chí cả Bash ... Các câu trả lời còn lại đơn giản là không hoạt động tốt. JavaScript nghe có vẻ quen thuộc, nhưng tin nói Nescaffe - vì vậy nó cũng không nên đi :) Ngay cả khi có sẵn, vì nhu cầu đơn giản của tôi - chúng sẽ quá mức và chậm.

Tuy nhiên, điều cực kỳ quan trọng đối với tôi là nhận được nhiều biến từ trả lời được định dạng json của modem. Tôi đang làm điều đó trong một sh ​​với BusyBox được cắt giảm rất nhiều tại các bộ định tuyến của tôi! Không có vấn đề khi sử dụng awk một mình: chỉ cần đặt dấu phân cách và đọc dữ liệu. Đối với một biến duy nhất, đó là tất cả!

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

Hãy nhớ rằng tôi không có mảng? Tôi đã phải gán trong dữ liệu được phân tích cú pháp awk cho 11 biến mà tôi cần trong tập lệnh shell. Bất cứ nơi nào tôi nhìn, đó được cho là một nhiệm vụ bất khả thi. Không có vấn đề với điều đó, quá.

Giải pháp của tôi rất đơn giản. Mã này sẽ: 1) phân tích tệp .json từ câu hỏi (thực ra, tôi đã mượn một mẫu dữ liệu làm việc từ câu trả lời được nâng cao nhất) và chọn ra dữ liệu được trích dẫn, cộng với 2) tạo các biến shell từ trong awk gán shell có tên miễn phí tên biến.

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"

Không có vấn đề với khoảng trống trong. Trong sử dụng của tôi, cùng một lệnh phân tích một đầu ra dòng đơn dài. Khi eval được sử dụng, giải pháp này chỉ phù hợp với dữ liệu đáng tin cậy. Thật đơn giản để điều chỉnh nó để lấy dữ liệu không được trích dẫn. Đối với số lượng lớn các biến, tốc độ tăng biên có thể đạt được bằng cách sử dụng khác nếu. Thiếu mảng rõ ràng có nghĩa là: không có nhiều bản ghi mà không cần thêm. Nhưng nơi có sẵn các mảng, việc điều chỉnh giải pháp này là một nhiệm vụ đơn giản.

@maikel sed trả lời gần như hoạt động (nhưng tôi không thể nhận xét về nó). Đối với dữ liệu được định dạng độc đáo của tôi - nó hoạt động. Không quá nhiều với ví dụ được sử dụng ở đây (thiếu dấu ngoặc kép ném nó đi). Nó là phức tạp và khó sửa đổi. Thêm vào đó, tôi không thích phải thực hiện 11 cuộc gọi để trích xuất 11 biến. Tại sao? Tôi đã tính thời gian 100 vòng lặp trích xuất 9 biến: hàm sed mất 48,99 giây và giải pháp của tôi mất 0,91 giây! Không đẹp? Chỉ thực hiện một trích xuất duy nhất gồm 9 biến: 0,51 so với 0,02 giây.


5

Bạn có thể thử một cái gì đó như thế này -

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

5

Bạn có thể sử dụng jshon:

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

Trang web cho biết: "Hai lần nhanh nhất, 1/6 bộ nhớ" ... và sau đó: "Jshon phân tích, đọc và tạo JSON. Nó được thiết kế để có thể sử dụng được từ bên trong vỏ và thay thế các trình phân tích cú pháp adhoc dễ vỡ được tạo từ grep / sed / awk cũng như các trình phân tích cú pháp một dòng nặng được làm từ perl / python. "
Roger

đây được liệt kê là giải pháp được đề xuất để phân tích cú pháp JSON trong Bash
qodeninja

cách dễ nhất để thoát khỏi các trích dẫn xung quanh kết quả là gì?
gMale

4

Đây là một cách bạn có thể làm với 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

Để phân tích cú pháp JSON phức tạp hơn, tôi khuyên bạn nên sử dụng mô-đun jsonpath python (của Stefan Goessner) -

  1. Cài đặt nó -

sudo easy_install -U jsonpath

  1. Sử dụng nó -

Ví dụ file.json (từ 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
    }
  }
}

Phân tích cú pháp (trích xuất tất cả các đầu sách có giá <10) -

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

Sẽ xuất -

Sayings of the Century
Moby Dick

LƯU Ý: Dòng lệnh trên không bao gồm kiểm tra lỗi. Để có giải pháp đầy đủ với việc kiểm tra lỗi, bạn nên tạo tập lệnh python nhỏ và bọc mã bằng thử ngoại trừ.


thành ngữ đẹp. Tôi thậm chí không biết Python, nhưng đây có vẻ là một giải pháp mạnh mẽ
Sridhar Sarnobat

Tôi đã gặp một chút khó khăn khi cài đặt jsonpathnên đã cài đặt jsonpath_rwthay vào đó, vì vậy đây là một cái gì đó tương tự bạn có thể thử nếu cách trên không hoạt động: 1) /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;"(Tôi đã sử dụng đường dẫn đầy đủ đến nhị phân python vì tôi gặp một số vấn đề với nhiều trăn Cài đặt).
Sridhar Sarnobat

4

Nếu bạn có php :

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

Ví dụ:
chúng tôi có tài nguyên cung cấp json với mã iso của các quốc gia: http://country.io/iso3.json và chúng tôi có thể dễ dàng nhìn thấy nó trong một vỏ với curl:

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

nhưng có vẻ không thuận tiện lắm, và không thể đọc được, phân tích cú pháp tốt hơn và xem cấu trúc có thể đọc được:

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

Mã này sẽ in một cái gì đó như:

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

nếu bạn có các mảng lồng nhau, đầu ra này sẽ trông tốt hơn nhiều ...

Hy vọng điều này sẽ hữu ích ...


4

Ngoài ra còn có một công cụ xử lý JSON CLI rất đơn giản nhưng mạnh mẽ fx - https://github.com/antonmedv/fx

Ví dụ về định dạng JSON trong thiết bị đầu cuối Bash

Ví dụ

Sử dụng chức năng ẩn danh:

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

Nếu bạn không vượt qua hàm ẩn danh param => ..., mã sẽ được tự động chuyển thành hàm ẩn danh. Và bạn có thể có quyền truy cập vào JSON bằng từ khóa này:

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

Hoặc chỉ sử dụng cú pháp dấu chấm quá:

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

Bạn có thể vượt qua bất kỳ số lượng hàm ẩn danh nào để giảm JSON:

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

Bạn có thể cập nhật JSON hiện có bằng cách sử dụng toán tử trải rộng:

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

Chỉ cần JavaScript đơn giản . Đừng cần học cú pháp mới.


CẬP NHẬT 2018-11-06

fxhiện có chế độ tương tác ( ! )

https://github.com/antonmedv/fx


7
Nếu bạn đang thúc đẩy sáng tạo của riêng bạn, bạn cần phải rõ ràng về nó. Xem Làm thế nào để không trở thành một người gửi thư rác.
tripleee

4

Đây là một câu trả lời khác bash& pythonlai. Tôi đã đăng câu trả lời này vì tôi muốn xử lý đầu ra JSON phức tạp hơn, nhưng, làm giảm độ phức tạp của ứng dụng bash của tôi. Tôi muốn bẻ khóa đối tượng JSON sau đây từ http://www.arcgis.com/shared/rest/info?f=json trong bash:

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

Trong ví dụ sau, tôi đã tạo ra cách thực hiện jqunquotetận dụng của riêng mình python. Bạn sẽ lưu ý rằng một khi chúng ta nhập đối tượng jsonpython từ từ điển python, chúng ta có thể sử dụng cú pháp python để điều hướng từ điển. Để điều hướng ở trên, cú pháp là:

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

Bằng cách sử dụng phép thuật trong bash, chúng tôi bỏ qua datavà chỉ cung cấp văn bản python ở bên phải dữ liệu, nghĩa là

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

Lưu ý, không có tham số, jq hoạt động như một trình giải mã JSON. Với các tham số, chúng ta có thể sử dụng cú pháp python để trích xuất bất cứ thứ gì chúng ta muốn từ từ điển bao gồm điều hướng các từ điển con và các thành phần mảng.

Dưới đây là một ví dụ hoạt động thể hiện ở trên:

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

Tôi đã thực hiện điều này, "phân tích" một phản hồi json cho một giá trị cụ thể, như sau:

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

Rõ ràng, $ url ở đây sẽ là url twitter và $ var sẽ là "văn bản" để nhận phản hồi cho var đó.

Thực sự, tôi nghĩ rằng điều duy nhất tôi làm OP đã bỏ qua là grep cho dòng với biến cụ thể mà anh ta tìm kiếm. Awk lấy mục thứ hai trên dòng, và với sed tôi lột dấu ngoặc kép.

Một người thông minh hơn tôi có lẽ có thể làm toàn bộ suy nghĩ với awk hoặc grep.

Bây giờ, bạn có thể làm tất cả chỉ với sed:

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

do đó, không awk, không grep ... Tôi không biết tại sao tôi không nghĩ về điều đó trước đây. Ừm ...


Trên thực tế, với sed bạn có thể làm
tonybaldwin

1
Các đường ống grep | awk | sedsed | sed | sedđường ống là các antipotype lãng phí. Ví dụ cuối cùng của bạn có thể dễ dàng được viết lại curl "$url" | sed '/text/!d;s/\"text\"://g;s/\"//g;s/\ //g'nhưng như những người khác đã chỉ ra, đây là cách tiếp cận dễ bị lỗi và dễ vỡ không nên được đề xuất ở nơi đầu tiên.
tripleee

Tôi đã phải sử dụng grep -oPz 'name \ ": \". *? \ "' Curloutput | sed 's / name \": / \ n / g'
Ferroao

3

Phân tích cú pháp JSON là đau đớn trong một kịch bản shell. Với ngôn ngữ phù hợp hơn, hãy tạo một công cụ trích xuất các thuộc tính JSON theo cách phù hợp với các quy ước về kịch bản lệnh shell. Bạn có thể sử dụng công cụ mới của mình để giải quyết vấn đề kịch bản shell ngay lập tức và sau đó thêm nó vào bộ công cụ của bạn cho các tình huống trong tương lai.

Ví dụ, hãy xem xét một công cụ jsonlookup sao cho nếu tôi nói jsonlookup access token idnó sẽ trả về id thuộc tính được xác định trong mã thông báo thuộc tính được xác định trong quyền truy cập thuộc tính từ stdin, có lẽ là dữ liệu JSON. Nếu thuộc tính không tồn tại, công cụ sẽ không trả về gì (thoát trạng thái 1). Nếu phân tích cú pháp thất bại, thoát trạng thái 2 và thông báo tới thiết bị lỗi chuẩn. Nếu tra cứu thành công, công cụ sẽ in giá trị của thuộc tính.

Đã tạo một công cụ unix cho mục đích chính xác là trích xuất các giá trị JSON, bạn có thể dễ dàng sử dụng nó trong các tập lệnh shell:

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

Bất kỳ ngôn ngữ sẽ làm cho việc thực hiện jsonlookup . Đây là một phiên bản python khá súc tích:

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

Một hai lớp lót sử dụng python. Nó hoạt động đặc biệt tốt nếu bạn đang viết một tệp .sh và bạn không muốn phụ thuộc vào một tệp .py khác. Nó cũng tận dụng việc sử dụng đường ống |. echo "{\"field\": \"value\"}"có thể được thay thế bằng bất cứ điều gì in một json đến thiết bị xuất chuẩn.

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

Câu hỏi không phải là tìm kiếm một giải pháp Python. Xem các bình luận, quá.
Andrew Barber

3

Đây là một usecase tốt cho pythonpy :

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

Thậm chí ngắn hơn, mô-đun python -c ở đây :) tốt đẹp.
m3nda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.