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

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

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

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

4回答

5895閲覧

bash:for文でSELECT文をgrepする方法について教えてください。

退会済みユーザー

退会済みユーザー

総合スコア0

bash

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

1クリップ

投稿2016/02/16 12:02

編集2016/02/16 16:14

###前提・実現したいこと
シェルスクリプトで、SQLが記載されたあるログファイルから各SELECT文の割合を算出したいです。
簡易的な割合のため、where句以降は省略してユニーク化させています。
仕組みとしては、ログファイルのSELECT文をユニーク化し、それを元にログファイルから各SELECT文の割合を算出したいと思っています。

###期待する結果。
#例 <SQL>,<行数>
SELECT cid, name, address FROM test1;,3
SELECT class, school FROM test2;,3
SELECT company, train, station FROM test3;,3

上記のような形で、対象のSQLとそのSQLがファイル内に存在する行数が表示されるようにしたいです。

###発生している問題・エラーメッセージ
セミコロンを区切り文字にしているのでクエリ毎に変数へ格納できているのですが
grepがうまくいかず、wc -lの結果で全行が返ってきてしまいます。
grep内の変数をダブルクォーテーションでくくってみた入りもしましたがうまくいきませんでした。(スペースがあるからでしょうか…

###ソースコード
使用例:./test.sh(以下のスクリプト) <ログファイル>

bash

1#!/bin/bash 2IFS_BACKUP=$IFS 3IFS=$';' ←セミコロンで区切り、for文の変数に格納しています。 4for n in $(sort ${1} | uniq | grep -i select | awk -F'\t' '{print $ 3}') 5do 6 echo "${n},$(grep ${n} ${1} | wc -l)" 7done 8IFS=$IFS_BACKUP
### ログファイル 1 162015 SELECT cid, name, address FROM test1; 2 162015 SELECT class, school FROM test2; 3 162015 SELECT company, train, station FROM test3; 1 162015 SELECT cid, name, address FROM test1; 2 162015 SELECT class, school FROM test2; 3 162015 SELECT company, train, station FROM test3; 1 162015 SELECT cid, name, address FROM test1; 2 162015 SELECT class, school FROM test2; 3 162015 SELECT company, train, station FROM test3;

###補足情報(言語/FW/ツール等のバージョンなど)
OS:CentOS6.7

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

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

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

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

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

otn

2016/02/16 15:17 編集

他人が再現できるように入力データを示してください。 あと、期待する出力結果も。 また、awkでタブを区切りに指定していますが、データ中にタブがあると言うことですか?
退会済みユーザー

退会済みユーザー

2016/02/16 16:15

色々と情報不足ですみません。ご推察の通りデータ中にタブが存在します。
guest

回答4

0

はじめに
もしかして、ログファイルはWindows上で作成されたものでは?
そして、スクリプトはCentOS上で作成していませんか?

説明
Windows上での改行コードは「CR+LF(\r\n)」になります。
対してCentOS(Linux)での改行コードは「LF(\n)」になります。
IFSへは直接改行を入力されているので「LF(\n)」が区切り文字になっていると思います。

結果として抽出したSQL分の;の後に「CR(\r)」が残ったままとなり、
"${n}"を出力後、行頭に移動して",$(grep "${n}" ${1} | wc -l)"の出力になるので
行頭から上書きする状態でカンマ以降が出力されるのだと思います。

ログファイルに対して以下のコマンドを実行すると確認できます。

bash

1$file sample.log 2sample.log: ASCII text, with CRLF line terminators

結果が上記の通りなら、これが原因かと思われます。

IFSの設定を以下のように変更すれば対応できると思います。
手元の環境(vagrantで構築したCentOS 6.7)での確認しました。

bash

1IFS=$'\r\n' 2# 制御コードを含めるときに$を付けます。 3# 2つ指定してますが個別に判定されるので、CR+LF、LFのどちらでも対応できます。 4# 区切り文字として読み捨てられる感じに。

あとは、実際のログファイルを確認できないので上記の状態でなければ不明です。

投稿2016/02/17 19:57

編集2016/02/17 21:35
StupidDog

総合スコア263

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

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

0

ベストアンサー

夜分にご覧いただいたのにすみません。
一応結果だけで言うと自己解決いたしましたので、その内容とともにご報告させていただきます。

まず、うまくgrepで抽出できていなかった原因ですが、改行がその原因のようでした。
よくよくデバッグ出力の結果を見ると、grepの直後に改行されていました。

bash

1++ grep '" ←ここで改行 2SELECT cid, name, address FROM test1;,3

そのため、スクリプトの区切り文字を';'→改行に変更することにしました。

bash

1*** wariai.sh.org 2016-02-16 08:25:52.855007303 -0800 2--- wariai.sh.org2 2016-02-16 08:28:00.410006453 -0800 3*************** 4*** 1,6 **** 5 #!/bin/bash 6 IFS_BACKUP=$IFS 7! IFS=$';' 8 for n in $(sort ${1} | uniq | grep -i select | awk -F'\t' '{print $ 3}') 9 do 10 echo "${n},$(grep "${n}" ${1} | wc -l)" 11--- 1,7 ---- 12 #!/bin/bash 13 IFS_BACKUP=$IFS 14! IFS=$' 15! ' 16 for n in $(sort ${1} | uniq | grep -i select | awk -F'\t' '{print $ 3}') 17 do 18 echo "${n},$(grep "${n}" ${1} | wc -l)"

しかし、区切り文字の変更が想定外の動作となりました。
<SQL>,<行数>という結果を期待していましたが、,<行数><SQL>という結果となり、しかもSQLの一部に侵食するように形が崩れていました。その結果が、以下です。

bash

1SELECT cid, name, address FROM test1;,3 ←期待する結果 2,3ELECT cid, name, address FROM test1; ←今回の結果

そこで、echoで出力する順番を以下のように変更しました。

bash

1*** wariai.sh 2016-02-16 08:06:21.895007284 -0800 2--- wariai.sh.org2 2016-02-16 08:28:00.410006453 -0800 3*************** 4*** 4,9 **** 5 ' 6 for n in $(sort ${1} | uniq | grep -i select | awk -F'\t' '{print $ 3}') 7 do 8! echo "$(grep "${n}" ${1} | wc -l),${n}" 9 done 10 IFS=$IFS_BACKUP 11--- 4,9 ---- 12 ' 13 for n in $(sort ${1} | uniq | grep -i select | awk -F'\t' '{print $ 3}') 14 do 15! echo "${n},$(grep "${n}" ${1} | wc -l)" 16 done 17 IFS=$IFS_BACKUP

その結果、当初の期待する結果の形とは違いますが、目的である、対象のSQLのそのログファイル内での割合(何行存在するか?)を割り出すことができました。

bash

13,SELECT cid, name, address FROM test1;

しかし、この理屈を理解できていず、結果オーライの状態になってしまっています。改行が影響していることはわかるのですが……

もし、この仕組みに心当たりある方がいらっしゃいましたらご教示いただけますと幸いです。

以上、よろしくお願いいたします。

投稿2016/02/16 16:40

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

StupidDog

2016/02/17 19:47 編集

ちょっと長くなったので回答へ…
guest

0

セパレータがセミコロン ; なのでしたら、

IFS=$';'

IFS=';'

としてみるとどうなりますか?

otnさまがご質問を出されている通り、情報が不足しているので正しい回答かどうかわからないまま手探りの回答となってしまいすみません。

投稿2016/02/16 14:57

Ken.sakanakana

総合スコア1768

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

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

otn

2016/02/16 15:15

bashでは ';' と $';' は同じですよ。つまり $ を付ける意味は無いのですが、取っても同じです。
guest

0

重複して回答してしまいましたので、こちらは削除しました。

投稿2016/02/16 14:56

編集2016/02/16 14:58
Ken.sakanakana

総合スコア1768

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

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

Ken.sakanakana

2016/02/16 14:59

最近回答ボタンを押しても反応が無い事が多く、時折二重にボタンを押してしまうことがあります。。。すみません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問