ほぼ同じ内容をn回もつログファイルから、最初の1回目だけを出力するPerlのワンライナー

 タイトルの通り、ほぼ同じ内容をn回持つログファイルから最初の1回目を取得して出力するPerlワンライナーを書きました。対象は200個近くあるログファイルになります。

ログファイルのイメージ

 ログファイルはこんな感じです。Oracleのautotraceの結果です*1。このログ自体は、実行計画+Elapsed timeを複数回取得するのが目的です。ほぼ同じ内容としたのは、Elapsed timeは若干ですがズレるためです。

6 rows selected.

Elapsed: 00:00:00.29

Execution Plan
----------------------------------------------------------
Plan hash value: 2988506077
....
------------------------------------------------------------------------------
| Id  | Operation          | Name     | Rows | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |          |    6 |   360 |     6  (17)| 00:00:01 |
|*  1 |  HASH JOIN         |          |    6 |   360 |     6  (17)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| EMPLOYEES|    6 |   204 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| JOBS     |   19 |   494 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
  1 - access("E"."JOB_ID"="J"."JOB_ID")
  2 - filter("E"."SALARY">12000)

Note
-----
  - dynamic sampling used for this statement

Statistics
----------------------------------------------------------
         0  recursive calls
         0  db block gets
        10  consistent gets
         0  physical reads
         0  redo size
       706  bytes sent via SQL*Net to client
       496  bytes received via SQL*Net from client
         2  SQL*Net roundtrips to/from client
         0  sorts (memory)
         0  sorts (disk)
         6  rows processed

 これがn回続きます。取得したいのは、最初の「6 rows selected.」から次の「6 rows selected.」までの間です。

6 rows selected.

(省略)

6 rows selected.

(省略)

6 rows selected.

(省略)

6 rows selected.

(省略)

6 rows selected.

(省略)

使用したPerlワンライナー

 こんなのgrep正規表現で一発や!と色々(10分程度)格闘した結果、うまくいかなかったのでPerlワンライナーで解決しました*2

$perl -ne '$l{$_}++; last if(/^(\d+|no) rows selected\.?$/ && $l{$_}==2); print $_;' hogehoge.log

 あとは標準出力をファイルにリダイレクトしてあげて。

$perl -ne '$l{$_}++; last if(/^(\d+|no) rows selected\.?$/ && $l{$_}==2); print $_;' hogehoge.log > unique_hogehoge.log

ファイルには以下のように1回めだけが出力されます。

6 rows selected.

(省略)

簡単な解説

perl -ne

 -eオプションでPerlワンライナーを利用可能にします。シングルコーテーション内がスクリプトになります。-nオプションで繰り返し=while相当です。つまり、$perl -neで「引数のファイルの内容で繰り返す」を表現しています。

$perl -ne 'print $_' hogehoge.log
# hogehoge.logの内容をすべて出力
$l{$_}++;

 ハッシュ$lにキー$_を設定して、インクリメントしています。$_は組み込み変数で宣言不要で使える変数です。今回の場合はwhileの引数にしているhogehoge.logの1行ずつが格納されています。hogehoge.logの内容が以下のように設定されているとして。

あああああ
いいいいい
ううううう
あああああ
あああああ
いいいいい

 出力回数のカウント+ファイルの内容を出力するワンライナーが簡単に作れたりします。Perlでユニークを作りたい時によく使うテクニックですね。。

perl -ne '$hash{$_}++; print "$hash{$_}: $_"' hogehoge.log

 出力結果は以下のとおり。

1: あああああ
1: いいいいい
1: ううううう
2: あああああ
3: あああああ
2: いいいいい
last if(/^(\d+|no) rows selected\.?$/ && $l{$_}==2);

 if内の処理が1行の場合は処理を先に書いて、処理の後にif文を書く構文が許容されます。本例の場合、ifに該当したらlast(whileを中断する)になります。if文の条件句では、「正規表現で狙った行にマッチする」かつ「ハッシュで2回目の登場」の場合としています。正規表現ブロックでは行が選択できた場合(\d+)と行が選択できない場合(no)を表現しています*3。これにより、最初の「6 rows selected.」から次の「6 rows selected.」まで間はwhile文を繰り返すを実現しています。

print $_

 解説不要、単なるprintですね。

Perlワンライナーについては

 ワンライナーが好きになったのは数年前にこのページを見てからです。UNIXLinuxユーザ必読。

 Perl1行野郎

*1:元ネタはTuning SQL*Plus

*2:grep解決版があれば教えて頂きたい

*3:no rows selectedの場合、末尾に「.」が付かないのはOracleのバグだと思います

スタイルシートでリスト要素をセンタリング+ボタンぽいデザインをつくる

 リスト要素をスタイルシートCSS)でセンタリングしてボタンぽいものをつくる、というデザインを仕事?でやりました。『要素をスタイルシートでセンタリング~』はナビゲーションバーなどの実装で必要になることがありますが、毎回忘れてしまうのでメモっておきます。

 

完成イメージ

f:id:suwork:20140821232300p:plain

 

HTMLソース*1

 HTMLソースは至ってシンプルです。divとul、li要素のみ。

<div class="centered">
  <ul class="labelblock">
   <li class="wakubase wakuhidari">リンク1</li>
   <li class="wakubase wakunaka">リンク2</li>
   <li class="wakubase wakunaka">リンク3</li>
   <li class="wakubase wakunaka">リンク4</li>
   <li class="wakubase wakunaka">リンク5</li>
   <li class="wakubase wakumigi">リンク6</li>
  </ul>
</div>

 

スタイルシートのソース

 スタイルシートはクラスごとにメモしておきます。

ul要素のlabelblockクラス

 リストをセンタリングするため、positionを「relative」、leftを「50%」、floatを「left」にします。『相対位置で、左寄せ、配置を左から50%=画面の中心』とします。paddingとmarginは余計なスペースをつくらないために記述しています。

ul.labelblock {
  position: relative;
  left: 50%;
  float: left;
  padding: 0px;
  margin: 0px;
}

li要素のwakubaseクラス

 li要素の基準となるクラスです。positionを「relative」、leftを「-50%」、floatを「left」にします。『相対位置で、左寄せ、-50%』とします。相対指定のため、基準(画面の中心)から左に-50%ずれるのでリスト要素が中心に配置されます。paddingはボタンぽい大きさにするため、よこならびのリストにするのでdisplayを「inline-block」で指定しています。その他はデザイン用なのでどうでも良い*2です。

li.wakubase {
  position: relative;
  left: -50%;
  float: left;
  padding: 4px 8px 4px 8px;
  display: inline-block;
  color: #909090;
  background-color: #EFEFEF;
  box-shadow: 0px -10px 4px 0px rgba(0, 0, 0, 0.09) inset;
  cursor: pointer;
}

ボタンぽいデザイン用のliクラス

 li要素の基準クラス、wakubaseにかぶせるようにデザイン用のli向けのクラスを作成します。wakuhidariクラス=ボタンの左端、wakunakaクラス=ボタンの中心部分、wakumigiクラス=ボタンの右端となります。wakubase:hoverはマウスを載せた時のデザイン変更用です。border-radiusを設定することで、左右を丸くしています。

li.wakuhidari {
  border-radius: 10px 0px 0px 10px;
  border-top: 1px solid #CCCCCC;
  border-bottom: 1px solid #CCCCCC;
  border-left: 1px solid #CCCCCC;
}

li.wakunaka {
  border-top: 1px solid #CCCCCC;
  border-bottom: 1px solid #CCCCCC;
  border-left: 1px solid #CCCCCC;
}

li.wakumigi {
  border-radius: 0px 10px 10px 0px;
  border: 1px solid #CCCCCC;
}

li.wakubase:hover {
  color: #FFFFFF;
  background-color: #CCCCCC;
}

スクロールバーを抑止するdivのcenteredクラス

 重要なクラスです。ul要素を画面の中心(50%地点)としているため、画面に表示されていませんが、50%右にはみ出ています。そのため、overflowを「hidden」として、はみ出た部分を表示しないようにします。指定しない場合、ブラウザの横スクロールバーが表示されてしまいます。

.centered {
  position: relative;
  overflow: hidden;
  margin: 0px;
}

 

参考

 以下のページを参考につくりました。floatうんぬんの説明はこちらを見たほうが良さげです。

floatで並べたリストのセンタリング - Weblog - Hail2u.net

*1:クラス名は適当です。気にしないように

*2:適切じゃない方の適当