[解決済み] 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'
また、Python のようなすでにシステムにインストールされているツールでこれを行うこともできます。
json
モジュール
そのため、適切なJSONパーサーの利点を生かしつつ、余分な依存関係を回避することができます。以下では、オリジナルのJSONがエンコードされているはずのUTF-8を使用することを想定しており、ほとんどの最新端末でも使用されているものです。
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仕様のシェル は非常に限定された言語であり、シーケンス(リストや配列)や連想配列(他の言語ではハッシュテーブル、マップ、ディクテ、オブジェクトとも呼ばれる)を表現する機能を備えていないのです。このため、移植可能なシェルスクリプトでは、JSONをパースした結果を表現するのがやや厄介になります。以下のようなものがあります。 ややハッキング的な方法 しかし、その多くはキーや値に特定の特殊文字が含まれると壊れてしまいます。
Bash 4以降、zsh、そしてkshは配列と連想配列をサポートしていますが、これらのシェルは普遍的に利用できるわけではありません(macOSはGPLv2からGPLv3への変更によりBash 3での更新を停止し、多くのLinuxシステムにはzshが箱から出してインストールされていません)。Bash 4 か zsh のどちらかで動作するスクリプトを書くことは可能です。zsh は最近の macOS、Linux、BSD システムのほとんどで利用可能ですが、このようなポリグロットスクリプトのために動作する shebang 行を書くのは大変でしょう。
最後に、シェルで本格的なJSONパーサーを書くとなると、jqやPythonのような既存の依存関係を代わりに使った方が良いくらい、重要な依存関係になります。良い実装をするためには、一行で、あるいは小さな5行のスニペットで済むものではありません。
なぜ awk や sed、grep を使わないのですか?
これらのツールを使って、形がわかっていて、1行に1つのキーというようにフォーマットが決まっているJSONから、いくつかの簡単な抽出をすることは可能です。他の回答に、このための提案の例がいくつかあります。
しかし、これらのツールは行ベースまたはレコードベースのフォーマット用に設計されており、エスケープ文字の可能性がある区切り文字にマッチした再帰的なパースには向いていません。
そのため、awk/sed/grep を使ったこれらの迅速で汚い解決策は壊れやすく、空白を折りたたんだり、JSON オブジェクトに追加の入れ子レベルを追加したり、文字列内にエスケープした引用を入れるなど、入力形式の一部が変わると壊れてしまう可能性が高いです。すべてのJSON入力を壊さずに処理できるほど堅牢なソリューションは、かなり大規模で複雑なものになります。
jq
やPythonを使うことができます。
私は以前、シェルスクリプトの入力解析がうまくいかず、大量の顧客データが削除されたことがあります。ですから、このように壊れやすいかもしれないクイック&ダーティな方法は決してお勧めしません。一回限りの処理であれば、他の回答も参考になりますが、やはりテスト済みの既存のJSONパーサーを使うことを強くお勧めします。
歴史的なメモ
この回答は、もともと
jsawk
と比べて、使い勝手が少し悪いです。
jq
また、Pythonよりも一般的ではないスタンドアロンの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'
関連
-
[解決済み] Twitter API エラー 215
-
[解決済み] 複数の配列を持つJSONオブジェクトを作るにはどうしたらいいですか?
-
[解決済み] 正しいJSONコンテンツタイプは何ですか?
-
[解決済み] JSONでコメントを使用することはできますか?
-
[解決済み] なぜGoogleはJSONレスポンスにwhile(1);を前置するのでしょうか?
-
[解決済み] cURLでJSONデータをPOSTするにはどうすればよいですか?
-
[解決済み] JavaScriptでJSONをきれいに印刷する
-
[解決済み] JSON文字列を安全にオブジェクトに変換する
-
[解決済み] PostgresでJSONフィールドにインデックスを作成するには?
-
[解決済み] ヘッダー値:application/vnd.api+json
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] TTLファイルフォーマット - これが何なのかさっぱり分からない
-
[解決済み] Golang で文字列を構造体のようにアンマーシャリングする
-
ジャクソン・ジャクソン・コア
-
[解決済み] kubectl get pods の json フォーマットの出力を jsonpath でパースする方法
-
[解決済み] Notepad++でJSONを再フォーマットする方法は?
-
[解決済み] JSON APIのレスポンス形式には規格がありますか?
-
[解決済み] ASP.NETでJSONを単純なDictionary<string,string>にデシリアライズするにはどうすればよいですか?
-
[解決済み] VS Codeで、"JSONではコメントが許可されていません "というエラーを無効にする。
-
[解決済み] どのようにjqを使用して2つのファイルから2つのJSONオブジェクトをマージするには?
-
[解決済み] JSON、REST、SOAP、WSDL、そしてSOA。これらはどのように結びついているのか