質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Q&A

解決済

3回答

6178閲覧

json形式のデータで、型をチェックする方法

teketeke

総合スコア46

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

4グッド

1クリップ

投稿2016/03/08 08:18

###前提・実現したいこと
現在、AWS S3から取得されるjson形式のデータの一部で、
StringではなくArray型になっているため、
スクリプトの処理がエラーになっているようです。
※cronで定期的にデータ取得をさせているのですが、エラーになっているデータがいまだに見つかっていない為、サンプルがありません...
※エラーメッセージの内容に関しては、別の質問(https://teratail.com/questions/28988)で質問させていただいており、回答をいただきました。

手動でデータをチェックして、削除・修正していられない(そもそもファイルが多くて見つかっていない)ので、
スクリプトで型をチェックして、処理をできないかと考えています。

json形式のデータで、型をチェックする方法はあるのでしょうか。

###発生している問題・エラーメッセージ
jq: error: Cannot iterate over string
jq: error: string and array cannot be sorted, as they are not both arrays

eventTime の部分でソートしようとしているので、eventTimeにArray型のデータが混ざっているのではないかと考えています。 ###ソースコード ```bash find /var/log/trail-log/ -name "*.json.gz" | sort | xargs gunzip -c | /usr/bin/jq '.[] | sort_by(.eventTime) | .[]' | /usr/bin/jq '{awsRegion, eventName, eventTime, userName: .userIdentity.userName, requestParameters}' | /usr/bin/jq '"[\(.eventTime)] \(.awsRegion) \(.userName) \(.eventName) \(.requestParameters)"' > trail.log ``` ###補足情報(言語/FW/ツール等のバージョンなど) ※cronで定期的にデータ取得をさせているのですが、エラーになっているデータがいまだに見つかっていない為、サンプルがありません...
EKD, dsk, ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

ワンライナーの処理とても、カッコイイです。

しかし、この処理の弱点
1.どのファイルでエラーになったかわからない。
2.gzip は、cpu負荷を与える処理であること
3.各 jq のどれが、エラーを出力したかわからない
bash は、if [ $? != 0 ]; then でエラーを見つけられる

テストしやすい処理、単体テスト可能な コーディングしないと、見えないですね。
数時間単位で 処理し 何週間もかかる処理を実行していると
gzip の解凍処理がフリーズしていることが何度かありました。
gzip と他の処理が重ならないようにすると、よいかもしれません。

あと、swap メモリが発生すると、いろいろ誤動作が発生します。
定期的に
メモリの解放

sudo sysctl -w vm.drop_caches=3

を することをお勧めします。

投稿2016/03/08 08:57

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

unau

2016/03/08 09:41

確かにエラーの原因が特定できていないのはワンライナーだからというのもありますね。 私もワンライナー好きなので多用しますが、使うとしたらインタラクティブなシェル上でちょっとした調査やささっとやりたい処理の場合であって、cron で起動するような堅牢性を求められるような処理にワンライナーは使いませんね。
teketeke

2016/03/09 02:00

回答いただきありがとうございます。 > テストしやすい処理、単体テスト可能な コーディングしないと、見えないですね。 おっしゃる通り、作成していた処理では、どこでエラーになっているのか不明で、処理を分けて確認する必要がありました。 今は、一旦エラーが発生するファイルを調査するスクリプトを作成し、少しずつファイルを確認しています。 > gzip の解凍処理がフリーズしていることが何度かありました。 年月日でログファイルのディレクトリ分けはされているので、日付毎にやっているのですが、 サーバスペックが低いせいかフリーズが多発してしまって、調査がなかなか進んでいません。 > あと、swap メモリが発生すると、いろいろ誤動作が発生します。 swapメモリ発生で誤動作が発生するのは知りませんでした...。 メモリについては定期的に開放するようにしてみます。
teketeke

2016/03/14 01:22

やっと原因のファイルが分かりました。 ファイルを調べたところ、AWSからのログではなく、誰かが別のログファイルをアップしていたため、処理できていませんでした。 ※目的毎にS3バケット分けたというのに、わざわざログファイル名を似せて作ってあって、解凍しないと分からないという面倒なことを...。 エラー原因のファイルは移動させたので、現在は正常に動作するようになりました。
guest

0

jqでsort_byできるのは配列に対してのみです。文字じゃだめです。
期待されるJSONは以下のようなものなのでしょう。

JSON

1{ 2 "data":[ 3 {"eventTime": xxxx, ...}, 4 : 5 ] 6}

最初の.[]でルート要素の値を抜き出しますが、それが配列でなくてはソートできません。
なのに何かしらの理由でJSONの内容が以下のようになるのでしょう:

JSON

1{ 2 "data": 例えばエラーメッセージとか 3}

ご質問の内容である型チェックですが、たとえば
もし本当に入力値から配列だけ抜き出したいのであれば、こんな感じ:

bash

1~ | jq '.[] | select(type == "array") | sort_by(.eventTime) | .[]' | ~'

これでエラーはでなくなるかもしれませんが、入力となるJSONの仕様について確認したほうがよいでしょう。

投稿2016/03/08 09:31

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teketeke

2016/03/09 01:59

回答いただきありがとうございます。 入力されるJSONですが、AWSのドキュメントをみると、sort_byできそうな形だったので、 実際にTrailのログを取得し、処理を動かしたところ、正常に処理されていたので、 別の型が入ってくることは想定していませんでした。 ※Trailのログには、インスタンスの削除等の操作のログが含まれているので、 仕様以外の値が入っているのは問題あると思うので、確認できれば、AWS側に確認してみたいと思います。 (技術サポートに入っていないので、相手してくれるかわかりませんが) http://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference.html 値の一部を xx にしていますが、実際のログの一部は以下になります。これはsort処理されます。 ```JSON { "Records": [ { "eventVersion": "1.03", "userIdentity": { "type": "IAMUser", "principalId": "xxxxxxxxxxxx", "arn": "arn:aws:iam::xxxxxxxxxxxx:user/test-user", "accountId": "xxxxxxxxxxxx", "accessKeyId": "xxxxxxxxxxxx", "userName": "test-user" }, "eventTime": "2016-02-23T13:23:26Z", "eventSource": "ec2.amazonaws.com", "eventName": "DescribeInstances", "awsRegion": "ap-northeast-1", "sourceIPAddress": "xxx.xxx.xxx.xxx", "userAgent": "aws-cli/1.9.7 Python/2.6.6 Linux/2.6.32-573.7.1.el6.x86_64 botocore/1.3.7", "requestParameters": { "instancesSet": {}, "filterSet": { "items": [ { "name": "instance-id", "valueSet": { "items": [ {} ] } } ] } }, "responseElements": null, "requestID": "a65f1950-6e0f-434e-a5e7-xxxxxxxx", "eventID": "0b86e943-00c5-43a6-944a-xxxxxxxx", "eventType": "AwsApiCall", "recipientAccountId": "xxxxxxxxxxxx" }, { "eventVersion": "1.03", "userIdentity": { "type": "IAMUser", "principalId": "xxxxxxxxxxxx", "arn": "arn:aws:iam::xxxxxxxxxxxx:user/test-user", "accountId": "xxxxxxxxxxxx", "accessKeyId": "xxxxxxxxxxxx", "userName": "test-user" }, "eventTime": "2016-02-23T13:22:49Z", "eventSource": "ec2.amazonaws.com", "eventName": "DescribeInstances", "awsRegion": "ap-northeast-1", "sourceIPAddress": "xxx.xxx.xxx.xxx", "userAgent": "aws-cli/1.9.7 Python/2.6.6 Linux/2.6.32-573.7.1.el6.x86_64 botocore/1.3.7", "requestParameters": { "instancesSet": {}, "filterSet": { "items": [ { "name": "instance-id", "valueSet": { "items": [ { "value": "i-xxxxxxxx" } ] } } ] } }, "responseElements": null, "requestID": "0230b135-25ee-465c-9a1f-xxxxxxxx", "eventID": "a9801b08-0c36-49cb-924e-xxxxxxxx", "eventType": "AwsApiCall", "recipientAccountId": "xxxxxxxxxxxx" }, { "eventVersion": "1.03", "userIdentity": { "type": "IAMUser", "principalId": "xxxxxxxxxxxx", "arn": "arn:aws:iam::xxxxxxxxxxxx:user/test-user", "accountId": "xxxxxxxxxxxx", "accessKeyId": "xxxxxxxxxxxx", "userName": "test-user" }, "eventTime": "2016-02-23T13:22:47Z", "eventSource": "ec2.amazonaws.com", "eventName": "DescribeInstances", "awsRegion": "ap-northeast-1", "sourceIPAddress": "xxx.xxx.xxx.xxx", "userAgent": "aws-cli/1.9.7 Python/2.6.6 Linux/2.6.32-573.7.1.el6.x86_64 botocore/1.3.7", "requestParameters": { "instancesSet": {}, "filterSet": { "items": [ { "name": "instance-id", "valueSet": { "items": [ { "value": "?i-xxxxxxxx?" } ] } } ] } }, "responseElements": null, "requestID": "2a66a476-3163-4b2f-88c0-xxxxxxxx", "eventID": "13959f9c-53af-4e93-abe4-xxxxxxxx", "eventType": "AwsApiCall", "recipientAccountId": "xxxxxxxxxxxx" } ] } ```
退会済みユーザー

退会済みユーザー

2016/03/09 02:37

べた張りされましても。私が回答で「期待されるJSON」と示した通りですね、としか。 その形であれば.[]で配列が返されてsort_byはされますよ?でもその形じゃなくて、.[]で文字列が返されてると思うのです。eventTimeの型関係ないですよ?
guest

0

jq コマンドは使ったことがないのですが、リファレンスを見ると、type という関数があるようです。これを使って、実際に eventTime の型を調べてみるといいのではないでしょうか。
あと、jq コマンドで制御文も書けるみたいですから型判定をしたうえで処理をすることもできるのではないでしょうか。
と、今のところ、ここまでしか言えませんが。

投稿2016/03/08 08:46

unau

総合スコア2468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teketeke

2016/03/09 02:03

回答いただきありがとうございます。 jqコマンドのリファレンス通り、typeで型が分かるみたいでした。 例: # gunzip -c a2.json.gz | /usr/bin/jq '.Records[].eventTime | type' "string" "string" "string" 判定については、selectやifでできそうですが、 判定と処理方法については、検証をしています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問