各地でOpen usp Tukubai を紹介すると、多くの人にとても興味を引かれることがある。
それは、Unix コマンドを自ら作っていくと言う習慣だ。
コマンドを作るということは、他言語で考えればifやfor等の予約語を追加するようなものかもしれない。そう考えると確かに興味深い。
だが、Unix の世界ではそれが当初のやり方だった。
コマンドを自作する文化。
この素晴らしさを、改めて伝えたい。
written by USPマガジン編集部
本記事は、USP MAGAZINE vol.7(2013年冬号)掲載記事のWEB再録記事(後半部分)です。
記事前半はこちら!
本記事掲載のUSP MAGAZINE vol.7は以下リンク先でご購入できます。
USP 研究所は、前時代を含めてこれまで2000 個にも及ぶコマンドを作ってきたという。多い日は1 日で10 個作ったこともあったのだとか。しかしそれら大半のコマンドが淘汰されていったことは、今のOpen usp Tukubai のコマンドの数を見れば容易に想像がつく。
「道具とは何たるか」などと偉そうなことを語っておきながらこれは一体どういうことか!とツッコミを入れたくなるところではあるが、そういう歴史があるからこそ道具の本質を見極め、そしてTukubai の思想を確立させられたのだろう。
そこでこの章では、そんな道具を夢見て生み出されながら淘汰されていったコマンドや、これから道具として活躍する可能性を秘めたコマンドなど、いくつか紹介していこう。
uniq コマンドの横方向版「横uniq」ということで登場したコマンドだ。その名のとおり、横方向にuniq がなされる。
1 2 3 4 5 |
> echo "aa bb bb bb bb bb1 cc" | yuniq aa bb bb1 cc > echo "aa bb bb bb cc bb" | yuniq aa bb cc bb > |
スペース区切りで、同じ綴りの文字列が連続してるとそれを一つに集約する。ただし、連続せずに出現したものに関しては集約されない。このあたりの仕様はuniq コマンドと同様に作られている。
以下に全体を掲載する。勿論cc でコンパイル可能だ。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
/* */ /* yuniq.c >>> C言語版YUNIQ */ /* */ /* Usage : yuniq < infile */ /* */ /* Written by N.Tounaka (usb-lab) */ #include <stdio.h> #include <string.h> #define BUFMAX 1024 char RECORD[BUFMAX],OUTBUF[BUFMAX]; void trim(); char *edit(); main(int argc,char **argv) { FILE *fp; /* 入力ファイルの取得 */ if(1 != argc) { if(NULL == (fp = fopen(argv[1],"r"))) { fprintf(stderr,"Error : %s ファイルがオープンできません.\n",argv[1]); exit(1); } } else fp = stdin; /* 各レコード処理 */ while(NULL != fgets(RECORD,BUFMAX,fp)) { trim(RECORD); /* 要BOF対策! */ strcpy(OUTBUF,edit(RECORD)); printf("%s\n",OUTBUF); } /* 読み取りエラーチェック */ if(!feof(fp) || ferror(fp)) { fprintf(stderr,"Error : 入力ファイル読み取りエラー.\n"); exit(1); } /* 終了 */ exit(0); } /* レコードのゴミを取る */ void trim(char *buf) { /* 行末の改行文字を削除 */ if('\n' == *(buf+strlen(buf)-1)) *(buf+strlen(buf)-1) = '\0'; /* 行末の空白を削除 */ /* 空白だけからなるデータへの対応が必要! */ while(' ' == *(buf+strlen(buf)-1)) *(buf+strlen(buf)-1) = '\0'; return; } /* yuniq 処理を行う */ char *edit(char *buf) { char wbuf[BUFMAX],rbuf[BUFMAX]; /* 要BOF対策! */ char old[100],new[100]; char *p,*q,*r; /* 作業領域の初期化 */ p = wbuf; strcpy(p,buf); r = rbuf; *r = '\0'; *old = *new = '\0'; /* 各フィールドを切り出す */ while(NULL != (q = strtok(p, " "))) { /* 前後のフィールドの受渡し */ strcpy(old,new); strcpy(new,q); /* 前のフィールドと異なっていたら連結 */ if(NULL != strcmp(old,new)) { strcat(r,new); strncat(r, " ",1); } p = NULL; } /* 最後の空白を削除する */ *(r+strlen(r)-1) = '\0'; return r; } |
yuniq 無しに横方向uniq をせよ、と言われたらどうやる だろうか。Tukubai コマンドを使えば次のように書ける。
1 |
> echo uniqしたい文字列 | tarr | uniq | yarr |
つまり、単語を一旦縦に並べてソートして、横に並べ直せばいいというわけだ。
横方向uniq の使用頻度がそう高くなかったために、ユニケージエンジニア達もこのコマンドを覚える機会がなかったうえ、たまに横方向uniq が必要になった時もtarr → uniq → yarr の組み合わせで事足りてしまったためにいつしか忘れ去られてしまった。