Edited at

Vim に惚れるシーン(ログファイル内の無駄な改行を除去する)

More than 3 years have passed since last update.


シーン 1

Yamaha ルータのログを採取した時、1行のログが長い場合には途中(80バイト)で改行文字が勝手に挿入されてしまいます。

2013/03/22 18:21:27: Power-on boot

2013/03/22 18:21:27: RTX1200 Rev.10.01.38 (Mon Jan 23 07:14:38 2012) starts
2013/03/22 18:21:27: main: RTX1200 ver=c0 serial=D261xxxxx MAC-Address=00:a0:d
e:xx:xx:xx MAC-Address=00:a0:de:xx:xx:xx MAC-Address=00:a0:de:xx:xx:xx
2013/03/22 18:21:34: LAN2: link up (1000BASE-T Full Duplex)
2013/03/22 18:21:45: PPPOE[01] PPPoE Connect
2013/03/22 18:21:45: PP[01] PPP/IPCP up (Local: 172.25.xx.x, Remote: 10.128.xx
x.x)
2013/03/22 18:22:34: LAN1: PORT1 link up (100BASE-TX Full Duplex)
2013/03/22 18:22:35: LAN1: link up
2013/04/12 00:02:22: PP[01] Detect down via LCP keepalive
2013/04/12 00:02:28: PPPOE[01] Disconnecting, cause [PPP: LCP Keepalive failure
]
2013/04/12 00:02:29: PPPOE[01] Disconnected, cause [PPP: LCP Keepalive failure]
2013/04/12 00:04:25: PPPOE[01] Connecting to PPPoE server
2013/04/12 00:05:10: PPPOE[01] PPPoE Connect
2013/04/12 00:05:11: PP[01] PPP/IPCP up (Local: 172.25.xx.x, Remote: 10.128.xx
x.x)
2013/05/17 10:49:53: Login succeeded for TELNET: 192.168.xxx.xxx
2013/05/17 10:57:15: 'administrator' succeeded for TELNET: 192.168.xxx.xxx
2013/05/17 11:02:15: Logout from TELNET: 192.168.xxx.xxx

ルータの設定で console column を長く設定してからログを採取すれば、この「無駄な改行」を回避できるのですが、既に採取してしまったログの中には、すでに「無駄な改行」が含まれている場合もあります。


どうしたい?

ログを調査するときには、この「無駄な改行」が邪魔になります。

本来の改行は残しつつ、「無駄な改行」のみを除去したいのですが、ログファイルが大きくて、とても手作業では…。

行の先頭が日時で始まらない行は、前の行にくっつけたいですね。


どうする?

Vim で簡単に解決。

「行の先頭が日時で始まらない行は、前の行にくっつけたい」を、そのまま Vim で実行しましょう。


いきなり答え

:v/^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d/-1j!

このコマンドを実行すると上のログがこのようになります。


  • 行頭が日時できれいに揃いました。

  • 分断されていた IP アドレスも正しく検索できるようになります。

2013/03/22 18:21:27: Power-on boot

2013/03/22 18:21:27: RTX1200 Rev.10.01.38 (Mon Jan 23 07:14:38 2012) starts
2013/03/22 18:21:27: main: RTX1200 ver=c0 serial=D261xxxxx MAC-Address=00:a0:de:xx:xx:xx MAC-Address=00:a0:de:xx:xx:xx MAC-Address=00:a0:de:xx:xx:xx
2013/03/22 18:21:34: LAN2: link up (1000BASE-T Full Duplex)
2013/03/22 18:21:45: PPPOE[01] PPPoE Connect
2013/03/22 18:21:45: PP[01] PPP/IPCP up (Local: 172.25.xx.x, Remote: 10.128.xxx.x)
2013/03/22 18:22:34: LAN1: PORT1 link up (100BASE-TX Full Duplex)
2013/03/22 18:22:35: LAN1: link up
2013/04/12 00:02:22: PP[01] Detect down via LCP keepalive
2013/04/12 00:02:28: PPPOE[01] Disconnecting, cause [PPP: LCP Keepalive failure]
2013/04/12 00:02:29: PPPOE[01] Disconnected, cause [PPP: LCP Keepalive failure]
2013/04/12 00:04:25: PPPOE[01] Connecting to PPPoE server
2013/04/12 00:05:10: PPPOE[01] PPPoE Connect
2013/04/12 00:05:11: PP[01] PPP/IPCP up (Local: 172.25.xx.x, Remote: 10.128.xxx.x)
2013/05/17 10:49:53: Login succeeded for TELNET: 192.168.xxx.xxx
2013/05/17 10:57:15: 'administrator' succeeded for TELNET: 192.168.xxx.xxx
2013/05/17 11:02:15: Logout from TELNET: 192.168.xxx.xxx

実際には、頭の中でこの答えを組み立てて実行するよりも、段階を踏んで組み立てていくほうが現実的です。(私の思考ではいきなり答えを見つけれないので)


段階的な答え

まず、日付で始まる行を検索してみましょう。



/^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d



これで、先頭が日時で始まる行がマッチします。

\d が4つ並ぶところは、\d\{4\} のようにも書けますが、4つ程度なら、\d\d\d\d とテンポ良く入力した方が思考が止まらなくて良いかもしれません。

実際には、「日時で 始まらない 行の 1行前 で、行連結(空白なし)を実行」すれば良いので…

:v//-1j!

簡単に説明すると…


  • 検索条件にマッチしない行に対する処理なので :v

  • 直前の検索条件を使うので、正規表現は省略できて //

  • その前の行に対する処理なので -1

  • 空白を挟まずに連結したいので j!normal gJ でも同じです)


まとめ

やりたいことが、素直に実行できる Vim に惚れました。

まだまだ「Vim に惚れるシーン」はあるハズです。