私はこのjsonテキストを持っています:
{
"buildStatus" : {
"status" : "ERROR",
"conditions" : [{
"status" : "OK",
"metricKey" : "bugs"
}, {
"status" : "ERROR",
"metricKey" : "test_success_density"
}, {
"status" : "OK",
"metricKey" : "vulnerabilities"
}
],
"periods" : []
}
}
BuildStatusの全体的なステータス、つまり予想される出力が「ERROR」であったことを抽出したい
"buildStatus" : {
"status" : "ERROR",
....
}
以下のsed式を試しましたが、機能していません。OK
を返します。
status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile
何が間違っていますか?
JSONやXMLなどの複雑なネストされたデータ構造を正規表現で解析しないでください。jshon
などの適切なJSONパーサーを使用してください。
最初にインストールする必要があります:
Sudo apt-get install jshon
次に、標準入力を介して解析するJSONデータを提供する必要があるため、別のコマンドの出力をパイプでリダイレクト(|
)するか、ファイルをリダイレクト(< filename
)できます。
必要なデータを抽出するために必要な引数は次のようになります。
jshon -e "buildStatus" -e "status" -u
-e "buildStatus"
は、トップレベルのディクショナリから「buildStatus」インデックスを持つ要素を選択します。-e "status"
は、上記で選択した第2レベルの辞書から「ステータス」インデックスを持つ要素を選択します。-u
は、選択したデータをJSONからプレーンデータに変換します(つまり、ここでは文字列の引用符を削除します)したがって、実行するコマンドは、データの取得元に応じて、次のいずれかのようになります。
jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u
jshon
の詳細については、オンラインでアクセスできるマンページ here を読むか、単にman jshon
と入力してください。
jq
のジョブ:
jq -r '.["buildStatus"]["status"]' file.json
以下に短縮できます。
jq -r '.buildStatus.status' file.json
-r
(--raw-output
)は、json
文字列の書式設定なしで、つまり引用符なしで文字列を出力します。
例:
% cat file.json
{
"buildStatus" : {
"status" : "ERROR",
"conditions" : [{
"status" : "OK",
"metricKey" : "bugs"
}, {
"status" : "ERROR",
"metricKey" : "test_success_density"
}, {
"status" : "OK",
"metricKey" : "vulnerabilities"
}
],
"periods" : []
}
}
% jq -r '.["buildStatus"]["status"]' file.json
ERROR
% jq -r '.buildStatus.status' file.json
ERROR
まだインストールされていない場合は、インストールしてください(ユニバースリポジトリで利用可能):
Sudo apt-get install jq
前述のように、適切なAPIを使用して複雑な構造化データを解析することをお勧めします。 Pythonにはそのためのjson
モジュールがあり、個人的にスクリプトで非常に多く使用しています。必要なフィールドを簡単に抽出できます。
$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' < input.txt
ERROR
ここで起こることは、入力ファイルをpythonのstdinにリダイレクトし、json.load()
でそれを読み取ることです。これは、キー「buildStatus」を持つpython辞書になり、「status」キーを持つ別のpython辞書が含まれます。したがって、別の辞書内に保存されている辞書のキーの値を出力しているだけです。かなり簡単です。
単純さは別として、別の利点は、pythonとこのAPIがすべてプリインストールされており、デフォルトでUbuntuに付属していることです。
canは実際にsed
でこれを行いますが、JSONデータを処理するためのツールを備えた、より洗練された言語を使用することを強くお勧めします。たとえば、Perlやpythonを試すことができます。
さて、あなたの簡単な例では、"status"
の最初の出現だけが必要なので、次のようにできます:
$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json
ERROR
トリックは-n
を使用して印刷を回避し、行がstatus
(/status/
)に一致する場合、必要な部分以外のすべてを削除しますs/.*:\s*"(.*)",/\1/
、p
rint行とq
uit。
個人的には、この同等のgrepコマンドがはるかに簡単であることがわかりました。
$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json
ERROR
またはこれ:
$ Perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json
ERROR
ただし、JSONファイルの解析を計画している場合は、手動でこれを実行しないでください。適切なJSONパーサーを使用します。
言っていないべきsed
を使用する(義務的な警告を書かないために誰かが私を投票したと思う)が、nextbuildStatus
への行は、あなた自身の試みで試みているように見えるので、sed
に次の行を読むようにN
に伝える必要があります。
$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR
-n
要求するまで何も出力しない-r
EREを使用(-E
と同じ)/buildStatus/N
このパターンを見つけて、次の行も読みますs/old/new/
old
をnew
に置き換えます.*
行の任意の数の文字\n
改行: "(.*)",
: "
と",
の間の文字を保存します\1
保存されたパターンへの後方参照p
作業したパーツを印刷しますJsonという別のJsonツール( https://github.com/trentm/json )
$ json buildStatus.status < file.json
ERROR
このケーススタディは誤解を招くものです。ツールが機能していないようです。 jsonファイルの変更にjson
を使用することもできます。
$ json -e 'this.buildStatus.status="not error"' < file.json > new.json
あるいは...
$ json -e 'this.buildStatus.status="no errors"' < file.json | json -e 'this.buildStatus.status
no errors
ドキュメンテーション: http://trentm.com/json/
インストールされていない場合:
npm install -g json
sed
および同様のテキストストリーム処理ツールがJSONやXMLなどの構造化データを解析するのに十分な装備を備えていない理由については、典型的な説明があります。私はそれを手元に持っていませんが、それはそこにあり、おそらく最も少数の状況を除くほとんどすべての状況で必要な表現はすぐに非常に複雑になりますが、構造を解析するために特別に構築された代替ツールはもっと同じ解析でエレガントで読みやすく、効率的です。
mur が commentに を入れたように、jq
はジョブに適したツールである必要があります。また、同じデータを解析してほとんど成功しないか、負担の大きい成功を収めようと何度か置き換えたのを見て、個人的に非常に興奮していることを保証できます。さらに、出力をフォーマットしたり、その他の方法で制御したりするための多くの機能が含まれています。私が現在忘れている理由またはそれ以上の理由で、jsontool
よりも好きです。
Byte Commander は 別の回答 でjshon
を推奨しているようです。私はそのツールを使用していませんが、xmlstarlet
とその構文を思い出させ、出力用にカスタマイズ可能なプレゼンテーションも提供します。