(Linux)expandのiオプションが何か分からない

3-2.加工

『マクロスΔ』(マクロスデルタ、MACROSS DELTA)の戦術音楽ユニット「ワルキューレ」が歌ってます。『マクロスΔ』は録画がたまるばかりで見ていないのですが(まとめて見る予定)、アニメは見ていないのになぜだかこの歌にやみつきになります。

ところで、ワルキューレはWalkureと書くみたいです。あれ、おかしい、確か綴りはValkyrieだったような……。
調べて見ると、Walkureはドイツ語のWalküreからとってるんですね。日本語では、WalkureもValkyrieも、ワルキューレ。

タブもスペースも空白ですので、見た目は同じ、しかしサイズやコマンドラインに与える影響が異なってきます。タブとスペースの使い分けができるとコマンド運びが一層スムーズになります。
expandは、タブを0〜複数個のスペースに置き換えるコマンドです。以下manの表示です。

名前
       expand - タブをスペースに変換する

書式
       expand [オプション]... [ファイル]...

説明
       各  FILE のタブをスペースに変換し、標準出力に書き出します。 FILE が指定
       されていないか - の場合は標準入力から読み込みます。

       長いオプションに必須の引数は短いオプションにも必須です。

       -i, --initial
              非空白類文字の後にあるタブを変換しない

       -t, --tabs=NUMBER
              タブの文字数を 8 個ではなく NUMBER 個にする

       -t, --tabs=LIST
              コンマ (,) で区切られた LIST にタブ位置を設定する

expandの確認のためにタブ入りテキストを使います。

~$ cat a
87	65	76	75
85	82	69	32
86	65	76	75
89	82	73	69
~$ 

ファイルaをパイプでexpandへ渡すと、

~$ cat a | expand
87	65	76	75
85	82	69	32
86	65	76	75
89	82	73	69
~$ 

タブもスペースを見た目は空白なので、何の変化もありません。このままではわかりにくいので、trコマンドでそれぞれを他の記号に置換して確認します。

スペースは、.(ドット)
タブは、_(アンダースコア)

に置換して確認してみましょう。
expandする前、expandした後、それぞれ見比べてください。

~$ cat a | tr '\t ' _.
87_65_76_75
85_82_69_32
86_65_76_75
89_82_73_69
~$ cat a | expand | tr '\t ' _.
87......65......76......75
85......82......69......32
86......65......76......75
89......82......73......69
~$ 

タブ1個に対して、スペースが6個に拡張(expand)されていますね。

expandはオプションなしで実行すると、タブ1つにつきスペースを最大8個に変換します(8タブ)。
一箇所文字数を増やして、expandを実行してみます。

~$ cat a | sed s/86/12345/ |expand | tr '\t ' _.
87......65......76......75
85......82......69......32
12345...65......76......75
89......82......73......69
~$ 

文字数を増やしても、綺麗にスペースに変換されました。では、8文字ちょうどはどうなるでしょうか。

~$ cat a | sed s/86/12345678/ |expand | tr '\t ' _.
87......65......76......75
85......82......69......32
12345678........65......76......75
89......82......73......69
~$ 

8個文字が連続した後のタブは、8個のスペースとなりました。

次は、オプションを使ってみます。
オプションは、-iと、-tがありますが、-iオプションの存在は知りませんでした(もう長く使っているはずなのに)。知ってる方の-tオプションから。
-tオプションは、タブを置き換える最大スペース数が指定できます。

~$ cat a | sed s/86/12345/ |expand -t4 | tr '\t ' _.
87..65..76..75
85..82..69..32
12345...65..76..75
89..82..73..69
~$ 

もう一つの使い方として、カンマで数字を区切ることで、各フィールドのカラム数を指定することができます。

~$ cat a | sed s/86/12345/ |expand -t4,9,20,25 | tr '\t ' _.
87..65...76.........75
85..82...69.........32
12345....65.........76...75
89..82...73.........69
~$ 

さて、次は-iオプションです。manはこうでした。


       -i, --initial
              非空白類文字の後にあるタブを変換しない

非空白類文字って何……。
とりあえず、使ってみましょう。

~$ cat a | tr '\t ' _.
87_65_76_75
85_82_69_32
86_65_76_75
89_82_73_69
~$ cat a | expand -i | tr '\t ' _.
87_65_76_75
85_82_69_32
86_65_76_75
89_82_73_69
~$ 

何も変化なしです。

非空白類文字の後にあるタブを変換しないのですから、「非」でなければ良いはずです。タブを2倍に増やして確認してみます。

~$ cat a | sed 's/\t/\t\t/g' | tr '\t ' _.
87__65__76__75
85__82__69__32
86__65__76__75
89__82__73__69
~$ cat a | sed 's/\t/\t\t/g' | expand -i | tr '\t ' _.
87__65__76__75
85__82__69__32
86__65__76__75
89__82__73__69
~$ 

ダメでした。変化なしです。

良くわからないので、expandコマンドのソースを確認します。
expandはcoreutilsにあるので、おそらくファイルは、expand.cです。
expand.cがfindで見つかったら、grepします。-iオプションについて調べたいので、caseとiが同一行の場所を確認します。caseの内の処理を確認するのが早いです。-A1オプションでcase時の処理も見てみます。

~$ apt-get source coreutils
~$ find coreutils-8.23/ -name expand.c
coreutils-8.23/src/expand.c
~$ grep -A1 'case.*i' coreutils-8.23/src/expand.c
        case 'i':
          convert_entire_line = false;
~$ 

なるほど。
上記検索結果、convert_entire_lineという変数にfalseを設定しています。
変数名の付け方が良いので、これだけで、このオプションの意味が分かりました。
entire、つまり一行まるまる変換するかどうかの変数で、-iオプションを指定した時は、false設定なので、一行まるまる変換しない、ということになります。

試してみましょう。

~$ cat a | sed 's/^/\t/' | tr '\t ' _.
_87_65_76_75
_85_82_69_32
_86_65_76_75
_89_82_73_69
~$ cat a | sed 's/^/\t/' | expand -i | tr '\t ' _.
........87_65_76_75
........85_82_69_32
........86_65_76_75
........89_82_73_69
~$ cat a | sed 's/^/\t\t/' | expand -i | tr '\t ' _.
................87_65_76_75
................85_82_69_32
................86_65_76_75
................89_82_73_69
~$ 

各行先頭だけ変換されました。

せっかく調べたのですが、この-iオプションを使うことはないかもしれません。なんせ今まで使ったことなかった上に、先頭タブの変換ならわざわざexpandを使わなくても良いですし。

ところで、実験に使っていたテキストですが、とある文字列の文字コードとなっています。

~$ tr \\t \\n < a | perl -ne 'print chr'
WALKURE VALKYRIE~$ 

「ワルキューレ」は見つけられたでしょうか。

コメント

タイトルとURLをコピーしました