Last-modified:2018/09/25 20:44:38.
TABle MANIpulator
% gem install tabmani
tabmani コマンドは表を扱うコマンドです。 デフォルトでは連続する空白区切りで要素ごとに、表示の桁を揃えます。 また、無駄な空白桁を減らしてコンパクトに出力するようにしています。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani
a b
ABC BCD CDE
12 34 56
行頭がインデントされている場合は、 ストリーム内で最小のインデント幅を基準とします。
% cat indent.dat
a ab
abc a
% cat indent.dat | tabmani
a ab
abc a
テーブルにするデータから特定の値を持つ行のみ抽出することができます。 以下は 1つめのカラムが a であるものを抽出します。 カラム番号は 1 から数え始めます。
% cat indent.dat | tabmani 1=a
a ab
このコマンドはファイル名を引数に取ることができません。 理由は、ファイルから取得するよりも、 絞り込み条件と解析対象を修正しつつ何度も実行して情報を掘り出すことがメインの目的で、 ファイルからのストリームを扱うことはあまりなさそうだと判断したためです。 ファイルからストリームをとるときは cat から パイプするなどしてください。
-t, –transpose オプションを付けると転置します。 要素数が合わない場合、そこには空文字が入ります。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani -t
a ABC 12
b BCD 34
CDE 56
-r, –right-just オプションで右詰めとなります。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani -r
a b
ABC BCD CDE
12 34 56
入力形式には以下が使えます。
ロングオプション | 短縮名 | 説明 |
---|---|---|
–input-blank | -b | 連続するスペースで区切る。 |
–input-csv | -c | CSV |
–input-column | 縦で半角スペースが貫通している(連続した)桁で区切る。 | |
–input-separator=CHAR | -s CHAR | セパレータ指定 |
1つめの「連続するスペースで区切る」というのはここまでで見てきたものです。 これがデフォルトです。
2つめの CSV, Comma-Separated Values は説明不要でしょう。 たとえば、
% cat csv.dat
a,ab
abc,a
% cat csv.dat| tabmani -c
a ab
abc a
3つめの「連続する縦でスペースが貫通している桁で区切る」というのは、 ps コマンドや ls コマンドのように縦に配列している形式です。 たとえば以下です。
% cat ls.dat
total 8
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 abcdefgh.txt
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 ijklmnop.txt
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 q r s t .txt
% cat ls.dat | tabmani
total 8
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 abcdefgh.txt
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 ijklmnop.txt
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 q r s t .txt
% cat ls.dat | tabmani --input-column
total 8
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 abcdefgh.txt
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 ijklmnop.txt
-rw-rw-r-- 1 ippei ippei 0 9月 25 14:08 q r s t .txt
まず第1ブロックの cat によるファイルの内容を示したものと、 第2ブロックでこれを tabmani に通したものを比較してみましょう。 1行目の 「total 8」と 4行目の「q r s t .txt」というファイル名のところに差違が見られます。 tabmani デフォルトでは(連続)スペースが区切りとなるので、 1行目は「total」が第1要素、「8」が第2要素と認識されます。 2行目以降は 第1要素が 10文字あるので、1行目の total と 8 の間が開いてしまっています。 また「q r s t .txt」という半角空白を含んだファイル名のために、q が abcdefgh.txt と対応する要素となって 「r」「s」「t」「.txt」がそれぞれ別の要素となってしまっています。 このため q と r の間が広くなってしまっています。
–input-column オプションは、 ストリーム全体を見て桁ごとに半角スペース以外の文字を含むかの判定を行い、 縦に貫通する半角スペースの桁を区切りにします。 この区切りが連続しているところは一まとまりにして一つの区切りにします。
このコマンドは等幅フォントによる表形式のテキスト出力を想定しています。 全ての行でスペースになっている桁は区切りの領域に属し、 どれかの行でスペース以外の文字が入っている桁は文字列の領域と見做します。 以下に例を示します。
abcde ghij lmn pq y
bc e ghi nopqr t yz
a cd k t xyz
--------------------------
ooooo oooooooooooo o ooo
--1-- -----2------ 3 -4-
上3行が解析対象の行です。 この場合、[f,k,s,u,v,w] に相当する桁が全ての行で空白になっているので区切りになります。 ただし、[u,v,w] の桁は一続きの区切りなので間に空文字列を要素として見做したりしません。 4, 5, 6 行目は説明のための文字列です。 5行目は 1〜3行の非空白文字の有無の投影となっています 6行目にキー番号を示しています。
4つめのセパレータ指定は、CSV に似ていますが、セパレータを自由に指定できるものです。 たとえば、
% cat bar.dat
a |b |
ABC|BCD|CDE
12 | 34|56
% cat bar.dat| tabmani -s '|'
a b
ABC BCD CDE
12 34 56
出力形式には以下が使えます。
ロングオプション | 短縮名 | 説明 |
---|---|---|
–output-column | 縦で半角スペースが貫通している桁で区切る。 | |
–output-csv | -C | CSV |
–output-mds | markdown の simple table | |
–output-tex | LaTeX の tabblar 環境 | |
–output-separator=CHAR | -S CHAR | セパレータ指定 |
ここまでに出てきたスタイルで、デフォルトです。
CSV に変換するには、 –output-csv を使います。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani --output-csv
a,b
ABC,BCD,CDE
12,34,56
Markdown の simple table フォーマットにするには、 –output-mds を使います。 mds は MarkDown Simple table から取っています。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani --output-mds
a b
--- --- ---
ABC BCD CDE
12 34 56
LaTeX の tabular 環境にするには、 –output-tex を使います。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani --output-tex
\begin{tabular}{lll}
\hline
a & b & \\
ABC & BCD & CDE \\
12 & 34 & 56 \\
\hline
\end{tabular}
任意の文字列をセパレータにすることができます。
% cat blank.dat
a b
ABC BCD CDE
12 34 56
% cat blank.dat | tabmani --output-separator='|'
a |b |
ABC|BCD|CDE
12 |34 |56
% cat blank.dat | tabmani --output-separator=' & '
a & b &
ABC & BCD & CDE
12 & 34 & 56
-a, –analyze オプションでセルの解析をします。
ps や qstat の出力は数千行以上にもなり得ます。 これらの表形式のストリームを簡単に取り纏めて把握するのに便利です。 example ディレクトリに実行例が同梱されています。 ps.dat は「ps auxw」 コマンドの出力サンプルで、以下のような長いファイルです。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 119924 6048 ? Ss 5月29 0:02 /sbin/init splash
root 17 0.0 0.0 0 0 ? S 5月29 0:00 [migration/2]
(snip)
alice 18586 0.0 0.0 53620 11268 pts/19 Ss 12:11 0:00 zsh
alice 18880 0.0 0.0 11276 2560 pts/19 S+ 12:13 0:00 less
root 18962 0.1 0.0 96124 6664 ? Ss 12:18 0:00 sshd: root [priv]
example/tableanalyze/ ディレクトリで以下のように実行すると、 以下のような出力が得られます。 –input-column オプションを入れないと、 COMMAND 列の空白が要素の区切りと見做されます。
% cat ps.dat | tabmani --input-column --analyze
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 119924 6048 ? Ss 5月29 0:02 /sbin/init splash
root 17 0.0 0.0 0 0 ? S 5月29 0:00 [migration/2]
root 46 0.0 0.0 0 0 ? S 5月29 0:00 [kdevtmpfs]
root 65 0.0 0.0 0 0 ? S 5月29 0:00 [fsnotify_mark]
root 163 0.0 0.0 0 0 ? S 5月29 0:00 [kworker/5:1]
root 188 0.0 0.0 0 0 ? S< 5月29 0:00 [bioset]
root 678 0.0 0.0 0 0 ? S< 5月29 0:00 [ext4-rsv-conver]
root 1072 0.0 0.1 450880 17516 ? Ssl 5月29 0:00 /usr/sbin/NetworkManager --no-daemon
alice 1943 0.0 0.0 126560 12716 ? Ss 5月29 0:01 i3
alice 2031 0.0 0.1 92596 19164 ? S 5月29 0:13 /usr/bin/uim-xim
alice 2042 0.0 0.0 80664 4924 ? S 5月29 0:21 i3status
alice 2057 0.0 0.0 276168 8160 ? Sl 5月29 0:00 /usr/lib/gvfs/gvfsd
alice 2075 0.0 0.0 83784 4172 ? S 5月29 0:00 urxvt
alice 2136 0.0 0.1 105260 16500 ? S 5月29 0:00 urxvt
root 2472 0.0 0.1 352260 18316 ? S 5月29 0:01 /usr/sbin/smbd -D
alice 4904 0.0 0.0 49044 10584 pts/2 Ss+ 5月29 0:00 -zsh
postfix 13890 0.0 0.0 67476 4424 ? S 11:52 0:00 pickup -l -t unix -u -c
root 15542 0.0 0.0 0 0 ? S 11:54 0:00 [kworker/u16:0]
root 15744 0.0 0.0 0 0 ? S 07:35 0:00 [kworker/7:2]
root 16567 0.0 0.0 0 0 ? S 08:44 0:00 [kworker/4:3]
root 17413 0.0 0.0 0 0 ? S< 10:03 0:00 [kworker/6:0H]
alice 17452 0.0 0.0 53648 11108 pts/3 Ss+ 10:08 0:00 zsh
root 17681 0.0 0.0 0 0 ? S 11:56 0:00 [kworker/3:1]
root 18011 0.0 0.0 0 0 ? S< 11:08 0:00 [kworker/7:2H]
root 18156 0.0 0.0 0 0 ? S< 11:25 0:00 [kworker/0:1H]
alice 18245 0.0 0.0 97076 12828 ? S 11:38 0:00 urxvt
alice 18287 0.0 0.0 83788 4072 pts/4 SN 11:39 0:00 urxvt
alice 18367 0.0 0.0 4508 844 ? S 11:41 0:00 /bin/sh -c urxvt
alice 18369 0.0 0.0 83784 4088 ? S 11:41 0:00 urxvt
alice 18374 0.0 0.0 98008 13944 ? S 11:58 0:00 urxvt
alice 18376 0.0 0.0 49060 10588 pts/17 Ss+ 11:58 0:00 zsh
alice 18479 0.4 0.1 177988 17692 pts/6 S+ 11:43 0:09 vim index.md
alice 18485 0.0 0.0 4508 844 ? S 11:44 0:00 /bin/sh -c urxvt
alice 18487 0.0 0.0 83784 4064 ? S 11:44 0:00 urxvt
alice 18489 0.0 0.0 4508 804 ? S 12:09 0:00 /bin/sh -c urxvt
alice 18491 0.0 0.0 83784 4060 ? S 12:09 0:00 urxvt
alice 18528 0.3 0.1 177520 16916 pts/16 S+ 12:09 0:01 vim bin/calc lib/tefil/calculator.rb
alice 18584 0.0 0.0 97036 12772 ? S 12:11 0:00 urxvt
alice 18586 0.0 0.0 53620 11268 pts/19 Ss 12:11 0:00 zsh
alice 18880 0.0 0.0 11276 2560 pts/19 S+ 12:13 0:00 less
root 18962 0.1 0.0 96124 6664 ? Ss 12:18 0:00 sshd: root [priv]
------- ----- ---- ---- ------ ----- ------ ---- ----- ---- ------------------------------------
1 2 3 4 5 6 7 8 9 10 11
key head types
1 USER 4
2 PID 42
3 %CPU 5
4 %MEM 3
5 VSZ 25
6 RSS 29
7 TTY 9
8 STAT 9
9 START 21
10 TIME 7
11 COMMAND 30
以下のように「—-」のようなバーと、その下の数字は表の列を扱うキーです。
------- ----- ---- ---- ------ ----- ------ ---- ----- ---- ------------------------------------
1 2 3 4 5 6 7 8 9 10 11
head は 1 行目における要素です。 多くのコマンドで列のタイトルとなっている事でしょう。 types はそれぞれの列におけるユニークな要素の種類数です。 たとえば 第1要素の USER は 4種類の名前がこの位置に現れたことを示しています。 PID は全てのプロセスで一意であるため、行数と同じになっている筈です。
各ユーザの出現数を調べてみましょう。 以下のように、解析したい対象のキー番号をコマンドライン引数に含めます。
% cat ps.dat | tabmani --input-column --analyze 1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 119924 6048 ? Ss 5月29 0:02 /sbin/init splash
(snip)
root 18962 0.1 0.0 96124 6664 ? Ss 12:18 0:00 sshd: root [priv]
------- ----- ---- ---- ------ ----- ------ ---- ----- ---- ------------------------------------
1 2 3 4 5 6 7 8 9 10 11
key head types
1 USER 4
2 PID 42
3 %CPU 5
4 %MEM 3
5 VSZ 25
6 RSS 29
7 TTY 9
8 STAT 9
9 START 21
10 TIME 7
11 COMMAND 30
key analysis
(key=1)
USER 1
postfix 1
root 17
alice 23
「key analysis」と書かれたブロックが表示されます。 key=1 に出現する 4 種類の要素は、 USER, postfix, root, alice であったことが分かります。 これらは、 ストリームのうちで出現する回数の昇順で表示されます。 USER は1行目のタイトルですね。
以下のように、複数のキーを一度に指定できます。
% cat ps.dat | tabmani --input-column --analyze 1 3
(snip)
key head types
1 USER 4
2 PID 42
3 %CPU 5
4 %MEM 3
5 VSZ 25
6 RSS 29
7 TTY 9
8 STAT 9
9 START 21
10 TIME 7
11 COMMAND 30
key analysis
(key=1)
USER 1
postfix 1
root 17
alice 23
(key=3)
%CPU 1
0.1 1
0.3 1
0.4 1
0.0 38
USER が alice の情報だけを取得し、他を捨てたいとしましょう。 以下のように、対象のキー番号と文字列をイコールで結んでコマンドライン引数に含めます。
% cat ps.dat | tabmani --input-column --analyze 1=alice
alice 1943 0.0 0.0 126560 12716 ? Ss 5月29 0:01 i3
alice 2031 0.0 0.1 92596 19164 ? S 5月29 0:13 /usr/bin/uim-xim
alice 2042 0.0 0.0 80664 4924 ? S 5月29 0:21 i3status
alice 2057 0.0 0.0 276168 8160 ? Sl 5月29 0:00 /usr/lib/gvfs/gvfsd
alice 2075 0.0 0.0 83784 4172 ? S 5月29 0:00 urxvt
alice 2136 0.0 0.1 105260 16500 ? S 5月29 0:00 urxvt
alice 4904 0.0 0.0 49044 10584 pts/2 Ss+ 5月29 0:00 -zsh
alice 17452 0.0 0.0 53648 11108 pts/3 Ss+ 10:08 0:00 zsh
alice 18245 0.0 0.0 97076 12828 ? S 11:38 0:00 urxvt
alice 18287 0.0 0.0 83788 4072 pts/4 SN 11:39 0:00 urxvt
alice 18367 0.0 0.0 4508 844 ? S 11:41 0:00 /bin/sh -c urxvt
alice 18369 0.0 0.0 83784 4088 ? S 11:41 0:00 urxvt
alice 18374 0.0 0.0 98008 13944 ? S 11:58 0:00 urxvt
alice 18376 0.0 0.0 49060 10588 pts/17 Ss+ 11:58 0:00 zsh
alice 18479 0.4 0.1 177988 17692 pts/6 S+ 11:43 0:09 vim index.md
alice 18485 0.0 0.0 4508 844 ? S 11:44 0:00 /bin/sh -c urxvt
alice 18487 0.0 0.0 83784 4064 ? S 11:44 0:00 urxvt
alice 18489 0.0 0.0 4508 804 ? S 12:09 0:00 /bin/sh -c urxvt
alice 18491 0.0 0.0 83784 4060 ? S 12:09 0:00 urxvt
alice 18528 0.3 0.1 177520 16916 pts/16 S+ 12:09 0:01 vim bin/calc lib/tefil/calculator.rb
alice 18584 0.0 0.0 97036 12772 ? S 12:11 0:00 urxvt
alice 18586 0.0 0.0 53620 11268 pts/19 Ss 12:11 0:00 zsh
alice 18880 0.0 0.0 11276 2560 pts/19 S+ 12:13 0:00 less
----- ----- --- --- ------ ----- ------ --- ----- ---- ------------------------------------
1 2 3 4 5 6 7 8 9 10 11
key head types
1 alice 1
2 1943 23
3 0.0 3
4 0.0 2
5 126560 18
6 12716 22
7 ? 8
8 Ss 6
9 5月29 11
10 0:01 5
11 i3 11
key analysis
(key=1=alice)
alice 23
「1=alice」という指定は、tabmani 全体のフィルタリング機能を使っています。 そのため、コマンドライン直下の表示も alice のものだけがフィルタリングされています。 その副作用で、1行目の要素タイトルが消えてしまっています。 1行目をタイトルとして特別扱いする(常に表示する・解析対象に含めず) には、 –title オプションを含めます。
% cat ps.dat | ~/git/tabmani/bin/tabmani --input-column --analyze --title 1=alice
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
alice 1943 0.0 0.0 126560 12716 ? Ss 5月29 0:01 i3
(snip)
alice 18880 0.0 0.0 11276 2560 pts/19 S+ 12:13 0:00 less
----- ----- ---- ---- ------ ----- ------ ---- ----- ---- ------------------------------------
1 2 3 4 5 6 7 8 9 10 11
key head types
1 USER 1
2 PID 23
3 %CPU 3
4 %MEM 2
5 VSZ 18
6 RSS 22
7 TTY 8
8 STAT 6
9 START 11
10 TIME 5
11 COMMAND 11
key analysis
(key=1=alice)
alice 23
複数条件による絞り込みもできます。 以下は alice による urxvt コマンドを抽出しています。
% cat ps.dat | ~/git/tabmani/bin/tabmani --input-column --analyze --title 1=alice 11=urxvt
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
alice 2075 0.0 0.0 83784 4172 ? S 5月29 0:00 urxvt
alice 2136 0.0 0.1 105260 16500 ? S 5月29 0:00 urxvt
alice 18245 0.0 0.0 97076 12828 ? S 11:38 0:00 urxvt
alice 18287 0.0 0.0 83788 4072 pts/4 SN 11:39 0:00 urxvt
alice 18369 0.0 0.0 83784 4088 ? S 11:41 0:00 urxvt
alice 18374 0.0 0.0 98008 13944 ? S 11:58 0:00 urxvt
alice 18487 0.0 0.0 83784 4064 ? S 11:44 0:00 urxvt
alice 18491 0.0 0.0 83784 4060 ? S 12:09 0:00 urxvt
alice 18584 0.0 0.0 97036 12772 ? S 12:11 0:00 urxvt
----- ----- ---- ---- ------ ----- ----- ---- ----- ---- -------
1 2 3 4 5 6 7 8 9 10 11
key head types
1 USER 1
2 PID 9
3 %CPU 1
4 %MEM 2
5 VSZ 6
6 RSS 9
7 TTY 2
8 STAT 2
9 START 8
10 TIME 1
11 COMMAND 1
key analysis
(key=1=alice)
alice 9
(key=11=urxvt)
urxvt 9
絞り込んだ上で、情報を解析することができます。 以下はさらに第8要素(STAT) の種類をリストアップしています。
% cat ps.dat | ~/git/tabmani/bin/tabmani --input-column --analyze --title 1=alice 11=urxvt 8
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
alice 2075 0.0 0.0 83784 4172 ? S 5月29 0:00 urxvt
alice 2136 0.0 0.1 105260 16500 ? S 5月29 0:00 urxvt
alice 18245 0.0 0.0 97076 12828 ? S 11:38 0:00 urxvt
alice 18287 0.0 0.0 83788 4072 pts/4 SN 11:39 0:00 urxvt
alice 18369 0.0 0.0 83784 4088 ? S 11:41 0:00 urxvt
alice 18374 0.0 0.0 98008 13944 ? S 11:58 0:00 urxvt
alice 18487 0.0 0.0 83784 4064 ? S 11:44 0:00 urxvt
alice 18491 0.0 0.0 83784 4060 ? S 12:09 0:00 urxvt
alice 18584 0.0 0.0 97036 12772 ? S 12:11 0:00 urxvt
----- ----- ---- ---- ------ ----- ----- ---- ----- ---- -------
1 2 3 4 5 6 7 8 9 10 11
key head types
1 USER 1
2 PID 9
3 %CPU 1
4 %MEM 2
5 VSZ 6
6 RSS 9
7 TTY 2
8 STAT 2
9 START 8
10 TIME 1
11 COMMAND 1
key analysis
(key=1=alice)
alice 9
(key=11=urxvt)
urxvt 9
(key=8)
SN 1
S 8
簡単な総和を取る方法を用意しています。 下に例を示します。 –sum=N とすると、 第N要素を縦に和を取っていきます。 文字列を数値として評価して総和を取ります。
% cat sum.dat
a 0 1 a
b 1 2.0 b
c 2 3 1
d 3 4 2
% cat sum.dat | tabmani --sum=1
a 0 1 a
b 1 2.0 b
c 2 3 1
d 3 4 2
---------
0
アルファベットのみの文字列は 0 と評価されるので、 –sum=1 による 第1要素の総和は 0 です。 「———」 という下線の下に総和が表示されます。
% cat sum.dat | tabmani --sum=2
a 0 1 a
b 1 2.0 b
c 2 3 1
d 3 4 2
---------
6
第2要素の和は 6。 整数のみで構成されている場合は結果を整数で出します。
% cat sum.dat | tabmani --sum=3
a 0 1 a
b 1 2.0 b
c 2 3 1
d 3 4 2
----------
10.0
第2要素の和は 10.0。 小数点が含まれていれば、結果を実数で出します。
% cat sum.dat | tabmani --sum=4
a 0 1 a
b 1 2.0 b
c 2 3 1
d 3 4 2
---------
3
アルファベットのみの文字列は 0 と評価されるので、結果的に 数と認識できる数のみの和になります。
表に書かれたデータをもとに再構成したいことはしばしばあります。 以下の表を見てみましょう。 VaspDir, finished, NELECT0 という要素は全ての要素に共通で、ほとんど情報を持っていません。 Ti, V の列が2種類、 Li0, Li1 の列が2種類で、2x2 の表を作ると良さそうです。
% cat reform.dat
VaspDir finished 1.23 Ti NELECT0 Li0
VaspDir finished 2.34 Ti NELECT0 Li1
VaspDir finished 3.45 V NELECT0 Li0
VaspDir finished 4.56 V NELECT0 Li1
まず、取り扱うためにキーを表示しましょう。 目でカウントすることもできますが、表示した方がラクでしょう。
% cat reform.dat| tabmani --show-key
VaspDir finished 1.23 Ti NELECT0 Li0
VaspDir finished 2.34 Ti NELECT0 Li1
VaspDir finished 3.45 V NELECT0 Li0
VaspDir finished 4.56 V NELECT0 Li1
------- -------- ---- -- ------- ---
1 2 3 4 5 6
表の横軸に 第4、 表の縦軸に 第6、 セルの値に 第3要素を用いるには、以下のように –reform オプション と 3つの引数を与えます。
% cat reform.dat| tabmani --reform 4 6 3
Ti V
Li0 1.23 3.45
Li1 2.34 4.56