Bashシェルスクリプトでcolumnコマンドを使って出力内容を表として整形する

2019-05-21Bash

はじめに

先日 Gibo のソースコードを見ていたときに出力内容を表形式で表示させる方法が参考になったので整理しました。

column というコマンドを利用します。

column コマンドはよく使っていたのですが、知らなかったオプションを知ることができたので紹介しておきます。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux
$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
$ column --version
column from util-linux 2.23.2

標準入力の列の位置を揃える

column -t のように、 -t オプションを追加することで列の位置を揃えた表として出力できます。

「4行x3列」 の簡単なデータファイルを作成し、これを操作してみます。

cat <<EOF >input.txt
$RANDOM $RANDOM $RANDOM
$RANDOM $RANDOM $RANDOM
$RANDOM $RANDOM $RANDOM
$RANDOM $RANDOM $RANDOM
EOF
$ cat input.txt
30378 11629 2969
210 23946 10935
27622 25085 14115
31836 1141 14077

ランダムな大小の数値が不規則に並んでいます。

このファイルに対して column -t コマンドを実行します。

$ cat input.txt | column -t
30378  11629  2969
210    23946  10935
27622  25085  14115
31836  1141   14077

きれいに整形されました。

ちなみに -o オプションを指定することで任意の区切り文字を指定可能です。

$ cat input.txt | column -t -o '|'
1730 |19697|30623
27783|16783|18083
6189 |17222|15585
499  |12456|29358

Vimでファイルを開いている場合、Visualモードで選択し :'<,'>!column -t -o '|' コマンドを実行すれば、Markdownを記述しているときに便利ですね。

CSVの列の位置を揃える

CSVのような特定の文字列でカラムが区切られているデータを表として出力してみます。

sortコマンドでCSVファイルをソートする場合はソート列の指定方法に注意 | ゲンゾウ用ポストイット でも利用したダミーデータ生成サービスを利用してCSVデータを作成し、表形式で出力してみます。

# ヘッダー行は次のようになっています。(今回はさほど重要ではありません)
## 連番,氏名,氏名(カタカナ),性別,年齢,取得ポイント
$ cat input.csv
1,小出里歩,オデリホ,女,27,85
2,吉野里紗,ヨシノリサ,女,38,894
3,本郷末治,ホンゴウスエジ,男,56,252
4,谷村千代乃,タニムラチヨノ,女,44,556
5,内野響子,ウチノキョウコ,女,44,170
6,塩谷貢,シオタニミツグ,男,34,494
7,児島愛子,コジマアイコ,女,39,675
8,白木俊史,シラキトシフミ,男,57,245
9,飯塚遥佳,イイヅカハルカ,女,20,974
10,阿久津清蔵,アクツセイゾウ,男,9,120

column -t -s , というように、 -t オプションに加えて -s で列の区切り文字を指定します。

ここではカンマ区切りですので -s , を指定します。

$ cat input.txt | column -t -s ,
1   小出里歩    オデリホ        女  27  85
2   吉野里紗    ヨシノリサ      女  38  894
3   本郷末治    ホンゴウスエジ  男  56  252
4   谷村千代乃  タニムラチヨノ  女  44  556
5   内野響子    ウチノキョウコ  女  44  170
6   塩谷貢      シオタニミツグ  男  34  494
7   児島愛子    コジマアイコ    女  39  675
8   白木俊史    シラキトシフミ  男  57  245
9   飯塚遥佳    イイヅカハルカ  女  20  974
10  阿久津清蔵  アクツセイゾウ  男  9   120

先程同様、列の位置が整えられて見やすく出力されています。

対象データを特定の列数で折り返して出力する

Gibo で使われていた機能がこちらです。

「1行 x 1列」で出力されるようなデータを「1行 x N列 」の表形式に出力します。
「1行 x 1列」では表示しきれないデータを1スクリーンに表示させることで閲覧性を高められます。

具体例を見ていきましょう。
seq コマンドに開始値と終了値を指定して、数値の連番を出力させてみます。
「1〜20」を出力させると以下のように20行として出力されます。

$ seq 1 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

column -x を使うと、各行の内容をいくつかまとめて1行にしてくれます。

以下の例では10行を1行にまとめて出力されています。

$ seq 1 20 | column -x
1       2       3       4       5       6       7       8       9       10
11      12      13      14      15      16      17      18      19      20

デフォルトでは各列は タブ (8文字幅)で区切られます。(先に取り上げた column -t コマンドの場合は「タブ」ではなく1個以上の「半角スペース」で区切られる点に違いがあります。)
また、 各行 の最大幅は 80文字 となっており、これを越えると予測された場合に折り返されます。

上記例では 各列 の幅がタブ込で8文字幅となっているため、 最大幅80文字 / 8文字幅 = 10列 となり10列表示可能です。

表示する列数を変更する

-c オプションで最大幅を指定可能です。
12列で表示したい場合には以下のようにオプションを指定します。

# 8文字幅 * 12列 = 最大幅96文字 を指定
$ seq 1 40 | column -x -c 96
1       2       3       4       5       6       7       8       9       10      11      12
13      14      15      16      17      18      19      20      21      22      23      24
25      26      27      28      29      30      31      32      33      34      35      36
37      38      39      40

各行の最大幅80文字を変更するためのもう一つの方法として、環境変数 COLUMNS の値を設定する方法があります。

$ echo $COLUMNS
102
# 最大幅72文字に設定する
$ export COLUMNS=$((8*9))
$ echo $COLUMNS
72
$ seq 1 40 | column -x
1       2       3       4       5       6       7       8       9
10      11      12      13      14      15      16      17      18
19      20      21      22      23      24      25      26      27
28      29      30      31      32      33      34      35      36
37      38      39      40

ただし、どうも column コマンドを実行するとこの環境変数の値が別の値に上書きされてしまうようです。
(コマンドを実行しているコンソール幅の実値で上書きされている?)

# 上記のコマンドを実行した直後に再度環境変数の値を確認するともとに戻ってしまう
$ echo $COLUMNS
102

ひとこと

ひとのソースコードを読むと学びが多いですね。

2019-05-21Bash