列の入れ替えはcutでできない、awkでできる

6-2.並び替え

(Linux入門はコチラ→中級者のためのLinuxコマンド入門)

cutコマンドで列の抽出ができます。
列の抽出ができるので、もっといろんなことが出来ると勘違いしやすいのですが、Unixコマンドは一つのことを上手くやるように設計されているので、cutも同様になんでもできるコマンドではありません。

cutコマンドで出来ること

cutコマンドはデフォルトでは、タブ区切りでフィールドを認識しますが、-dオプションでフィールドの区切り文字を指定することができます。
区切り文字として、:(コロン)を指定して確認してみます。

takk~$ echo AAA:BBB:CCC | cut -d: -f2
BBB
takk~$ 

フィールドは複数指定することもできます。ただし、デリミタも表示されていまいます。

takk~$ echo AAA:BBB:CCC | cut -d: -f1,3
AAA:CCC
takk~$ 

出力時のデリミタを変更するにはロングオプションが必要になります。

takk~$ echo AAA:BBB:CCC | cut -d: -f1,3 --output-delimiter=" "
AAA CCC
takk~$ echo AAA:BBB:CCC | cut -d: -f1,3 --output-delimiter="___"
AAA___CCC
takk~$ 

cutコマンドでは、フィールドを複数指定することはできても、それは別々のフィールドであり、同一フィールドは使用できません。

takk~$ echo AAA:BBB:CCC | cut -d: -f1,3,1
AAA:CCC
takk~$ 

出力は必ず入力順序で表示されますので、列の入れ替えを行うこともできません。

takk~$ echo AAA:BBB:CCC | cut -d: -f3,1
AAA:CCC
takk~$ 

次は以下のようなバイナリダンプの結果をcutでフィルタしてみます。

takk~$ hd a.bin
00000000  01 02 03 04 05 06 07 08  09 0a 0b 0c 0d 0e 0f 10  |................|
00000010  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
00000020  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
00000030  31 32 33 34 35 36 37 38  39 3a 3b 3c 3d 3e 3f 40  |123456789:;<=>?@|
00000040  41 42 43 44 45 46 47 48  49 4a 4b 4c 4d 4e 4f 50  |ABCDEFGHIJKLMNOP|
00000050  51 52 53 54 55 56 57 58  59 5a 5b 5c 5d 5e 5f 60  |QRSTUVWXYZ[\]^_`|
00000060  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000070  71 72 73 74 75 76 77 78  79 7a 7b 7c 7d 7e 7f 80  |qrstuvwxyz{|}~..|
00000080
takk~$ 

左の8桁がアドレス、空白を2個置いて、1バイト目が始まっていますが、この空白2個というところが、cutに取っては使いにくいテキストデータとなります。
デリミタを空白にして、フィールドを1から順に指定してみましょう。

takk~$ hd a.bin | cut -d' ' -f1
00000000
00000010
00000020
00000030
00000040
00000050
00000060
00000070
00000080
takk~$ 
takk~$ hd a.bin | cut -d' ' -f2








00000080
takk~$ hd a.bin | cut -d' ' -f3
01
11
21
31
41
51
61
71
00000080
takk~$ 

-f2の指定では何も表示されず、-f3でようやくデータの一列目が表示されました。
空白文字をデリミタとした場合、空白が2つ続くテキストでは、””(何もない文字列”がフィールドデータとされたからです。
このように、cutは規則正しく区切り文字と文字列が存在するテキスト(できればタブ区切り)に向いています。

cutがダメならawkって手もある

一方awkでは、連続する空白もデリミタとして認識することができますので、2番目のフィールドを抽出したい場合は、$2をprintするだけで実現できます。

takk~$ hd a.bin | awk '{print $2}'
01
11
21
31
41
51
61
71

takk~$ 

また、cutではできない列の入れ替えも可能です。

takk~$ hd a.bin | awk '{for(i=0;i<16;i+=2){ tmp=$(i+2);$(i+2)=$(i+3);$(i+3)=tmp }print}'
00000000 02 01 04 03 06 05 08 07 0a 09 0c 0b 0e 0d 10 0f |................|
00000010 12 11 14 13 16 15 18 17 1a 19 1c 1b 1e 1d 20 1f |............... |
00000020 22 21 24 23 26 25 28 27 2a 29 2c 2b 2e 2d 30 2f |!"#$%&'()*+,-./0|
00000030 32 31 34 33 36 35 38 37 3a 39 3c 3b 3e 3d 40 3f |123456789:;<=>?@|
00000040 42 41 44 43 46 45 48 47 4a 49 4c 4b 4e 4d 50 4f |ABCDEFGHIJKLMNOP|
00000050 52 51 54 53 56 55 58 57 5a 59 5c 5b 5e 5d 60 5f |QRSTUVWXYZ[\]^_`|
00000060 62 61 64 63 66 65 68 67 6a 69 6c 6b 6e 6d 70 6f |abcdefghijklmnop|
00000070 72 71 74 73 76 75 78 77 7a 79 7c 7b 7e 7d 80 7f |qrstuvwxyz{|}~..|
00000080                
takk~$ 

コメント

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