スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[C言語Tips]パイプが連結可能なコマンドの実装と条件 (2/2)

(1/2)へ移動する

仕事→ブログ更新→仕事というサイクルが定着してきてもうかれこれ2ヶ月にもなるのかと思うと感慨深いものがあります。

こんなことを考えていたらふと、教授が言っていた言葉を思い出しました。
私は「時間ができたらやりたいです」そんなことを言ったのだと思います。

すると教授は笑って、「その”いつか”はいつ来るんだい?」と言いました。
私がバツの悪そうな表情で笑っていると、教授はこんなことを言いました。

 「いいかい?砂塵くん。忙しさの中で身を置くことだよ。人間時間が出来た時には別のことをするものなんだ。
暇は持て余すものなんだ。常に忙しくありなさい。そして、その中でリズムを作りなさい」

そう言うと教授はなおも笑ってこう締めくくりました。

 「そしたらきっと多くがこなせるから、そしたらその”いつか”は必ず来るから」

 私は今、どんなリズムの中に居るのだろうか。そんなことを思う今日この頃、どうも、砂塵です。


早速行きましょう。

まず、標準入力が切り替わっていたら入力を読み込みそうでなければ文字を出力するプログラムの例を示します。


#include <stdio.h>
#include <io.h>

static const int BUF_SIZE = 256;

int main ()
{
char buf[BUF_SIZE];

//標準入力がキーボード以外に設定されていたら1行読み込む
if(!_isatty(_fileno(stdin)))
{
if (fgets(buf , sizeof(buf) , stdin))
{
//読み込んだ文字の後ろに"+ 1"と言う文字列を追加して出力
printf("%s + 1" , buf);
}
}
else
{
//そうでなければ標準出力に文字を出力
fputs("test" , stdout);
}

return 0;
}


isatty()は標準入出力を表す整数を指定すると標準入出力が端末を指している時には1を、そうでない時には0を返す関数です。端末とは出力で言えばディスプレイ、入力で言えばキーボードです。
そのため、isatty()の結果が0の時は指している先が端末ではない、つまり標準入出力がリダイレクトされているということです。

このプログラムを以下のように実行してみて下さい。


hoge.exe | hoge.exe | hoge.exe


| hoge.exeの個数は好きな数で構いません。
すると、実行回数に従ってtestという文字列に"+ 1"という文字列が追加されていると思います。
これはまず、最初のプログラムあkら"test"という文字列が次のプログラムへ送られ、次のプログラムがその"test"を読み込み、今度は"test + 1"を次のプログラムへと送ります。これはパイプによる連結が続く限り行われるのでパイプの連結数に応じて"+ 1"の数が増えるという仕掛けです。

この時のポイントはこの仕組を応用すればある一定の規約さえ守ればプログラム同士を組み合わせることが可能だということです。

例えばテキスト中の文字列を辞書順に並べ替えして、上位n項目(nは任意の数)を出力するプログラムを想定したとしましょう。

まず、並べ替えは既にsortというコマンドが存在していてこれの標準入力をファイルへリダイレクトしてやればこの点については解決です。早速やってみましょう。
まずsample.txtに以下のテキストが保存されています。

tiger
python
fox
dog
hen
camel
falconine
dack
hippopotamus
pheasant


それに対して

sort < sample.txt


これで先程のテキストが昇順にソートされて画面に出力されたと思います。
あとやりたいのはこの結果の上位n項目の取り出しです。
これは与えられたテキストをn回読み込むだけのコードを書けばよいということになります。

つまり以下のようなソースコードを作成します。
なお、読み込む回数nはここではこのソースコード内で定義してしまいます。

#include <stdio.h>
#include <io.h>

static const int BUF_SIZE = 256;

int main ()
{
char buf[BUF_SIZE];
int n = 3;

//標準入力がキーボード以外に設定されていたら1行読み込む
if(!_isatty(_fileno(stdin)))
{
//n回読み込む
for (int i = 0; i < n; ++i)
{
if (fgets(buf , sizeof(buf) , stdin))
{
fputs(buf , stdout);
}
else
{
//基底回数前に読み込む文字列がなくなったらループを抜ける。
break;
}
}
}

return 0;
}


ここでは3回標準入力から文字列を読み込んでいます。
このプログラムを以下のように実行します。


sort < sample.txt | hoge.exe


これで上位3項目のみが画面に出力されます。勿論、さらに

sort < sample.txt | hoge.exe > result.txt

とすれば結果をファイルに保存できます。

ちなみにこれでも良いには良いですが、正直、読み込む行数が変わる度にプログラムを作り直すのはナンセンスです。
そこでプログラムを以下のように書き換えます。

#include <stdio.h>
#include <stdlib.h>
#include <io.h>

static const int BUF_SIZE = 256;

int main (int argc , char **argv)
{
char buf[BUF_SIZE];
int n = 0;

//hoge.exe xxxxx
//xは任意の文字
if (argc == 2)
{
//文字列を数字に変換する。変換不能の文字の時は0を返す。
//意外と危ない関数で、よく槍玉にされるが、今回は簡略化のために使用する。
n = atoi(argv[1]);

if (n == 0)
{
puts("1以上の整数を指定して下さい。");
return -1;
}
}
else
{
fputs("Usage:hoge 読込回数\n", stderr);
}

//標準入力がキーボード以外に設定されていたら1行読み込む
if(!_isatty(_fileno(stdin)))
{
//n回読み込む
for (int i = 0; i < n; ++i)
{
if (fgets(buf , sizeof(buf) , stdin))
{
fputs(buf , stdout);
}
else
{
//基底回数前に読み込む文字列がなくなったらループを抜ける。
break;
}
}
}

return 0;
}


これはコマンドライン引数と言ってプログラムに対してパラメータを渡す方法を利用した読み込みプログラムです。
コマンドライン引数は常に文字列で渡されるのでそれをプログラム中で数字に変換してnの値年て利用しています。
これでファイル中の任意のn行を取り出すことができます。これを利用して以下のようなことも可能です。

hoge 5 < sample.txt | sort | hoge 1


これはファイルから5行読み込み、それを並び替えてその上位1つを取り出すという事を行っています。
ソースを書き換え無くても全く異なった結果が得られると言う点で、このようなプログラムの作り方が非常に柔軟性に富んでいることが分かるかと思います。

余談ですが、受け取る側で画像ファイルを処理できるようにしてやると、画像ファイルの内容を標準出力に投げることで画像のフィルタリングをパイプしたりできます。
OpenCVなどを使うと簡単にできますので、次回更新する際には、そのプログラムだけでも公開したいと思います。

それではまた次回。
スポンサーサイト

コメントの投稿

非公開コメント

twitter
    follow me on Twitter
    プロフィール

    砂塵

    Author:砂塵
    GIMP2でお絵描きしています。
    主にイラスト練習、プログラミングなどを扱っているブログです。

    Skype始めました。
    SkypeID:sazinn-gimp
    出没時間:平日21~26時、休日(土・日)

    Pixivはじめました
    微エロな絵を載せることがありますので、そういうのが苦手な方や嫌悪感を覚える方はご注意ください。

    カテゴリ
    リンク
    最新記事
    月別アーカイブ
    最新コメント
    RSSリンクの表示
    FC2カウンター
    FC2ブログランキング

    FC2Blog Ranking

    参加ブログカテゴリ
    にほんブログ村 IT技術ブログ プログラム・プログラマーへ
    にほんブログ村 イラストブログ イラスト練習へ
    上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。