リダイレクト(出力)

プログラムの結果の出力先を変えることをリダイレクトという。

https://www.kushiro-ct.ac.jp/yanagawa/C-2015/26-0722/index.html
もう一度基礎からC言語 第9回 制御構造と変数(5)~forとwhileに関するあれこれ 入出力の切り替え~リダイレクトとパイプ

src.cは、

printfは、"ABCDE"を標準出力で出力するだけ。

$ vi src.c
$ gcc src.c -o src
$ ./src
ABCDE
$ ./src > test.txt
$ ls
src  src.c  test.txt
$ cat test.txt
ABCDE
$

srcをそのまま実行すると、標準出力に"ABCDE"が出力されるだけ。
しかし、'>'とtest.txtを追加することで、ファイルtest.txtに"ABCDE"を出力するようになる。

Sample/c/redirect/out/src/redirect at master · bg1bgst333/Sample · GitHub

パイプライン

コマンドとコマンドの間にパイプ('|')を入れることで、最初のコマンドから、次のコマンドに結果を渡すことができる。
pipeシステムコールはこのパイプを扱うものだが、pipeでなくてもコマンドを受け取ることはできる。
コマンドを受け渡していくパイプのつながりをパイプラインという。

パイプライン処理・標準入出力によるデータ処理

最初のコマンドとなるsrcプログラムのsrc.cは、

ただ、"ABCDE"を出力するだけ。

受け取るコマンドとなるdestプログラムのdest.cは、

fgetsで標準入力stdinからsrcコマンドの結果を受け取る。
受け取った結果をbufに格納し、出力。

$ vi src.c
$ gcc src.c -o src
$ vi dest.c
$ gcc dest.c -o dest
$ ls
dest  dest.c  src  src.c
$ ./src
ABCDE
$ ./dest
abc
-----dest start-----
abc
-----dest end-----
$ ./src | ./dest
-----dest start-----
ABCDE
-----dest end-----
$

srcだけ実行すると、"ABCDE"を出力。
destだけ実行すると、入力待ちになるので"abc"を入力、すると"dest start"と"dest end"の間に"abc"が出力される。
srcとdestの間にパイプ('|')を入れると、srcの標準出力"ABCDE"が標準入力としてdestに渡されるので、"dest start"と"dest end"の間に"ABCDE"が出力される。

Sample/c/pipeline/pipeline/src/pipeline at master · bg1bgst333/Sample · GitHub

FILE

改めて、FILE型(FILE構造体)について調べていく。

Man page of FOPEN
Bioinformaticsのお勉強: ファイル記述子、ファイル型、ファイルポインタ、stdin、stdout、stderrについての考察

stdio.h
stdio.h

/usr/includeに移動してstdio.hを開く。

FILEで検索
FILEで検索

"FILE"で検索。

bits/typesの下にありそう
bits/typesの下にありそう

bits/typesの下にありそう。

FILE.hや__FILE.hやstruct_FILE.hにありそう。
FILE.hや__FILE.hやstruct_FILE.hにありそう。

FILE.hや__FILE.hやstruct_FILE.hにありそう。

FILE.hを見ると、

実態は_IO_FILE
実態は_IO_FILE

実態は、struct _IO_FILE。
__FILE.hを見ると、

こちらもstruct _IO_FILE
こちらもstruct _IO_FILE

こちらもstruct _IO_FILE。
struct_FILE.hを開いて、

_IO_FILEで検索
_IO_FILEで検索

_IO_FILEで検索すると、

これが本体っぽい
これが本体っぽい

これが本体っぽい・・・。
_filenoがファイルディスクリプタかな。
というわけで、_filenoを出力してみる。

fp->_filenoという感じでアクセスできて、ファイルディスクリプタの値だったら・・・。

$ vi FILE.c
$ ls
FILE  FILE.c  test.txt
$ gcc FILE.c -o FILE
$ ./FILE
fp->_fileno = 3
$

0は標準入力、1は標準出力、2は標準エラー出力、で予約されているので、3が出てくるということは、これがファイルディスクリプタだろう。

Sample/c/FILE/FILE/src/FILE at master · bg1bgst333/Sample · GitHub

ハッシュ

ハッシュ(連想配列ともいう)は、添字に文字列を指定することができ、文字列をキーとして値を取得できるデータ構造。

Perlのハッシュを理解しよう - Perl入門ゼミ

Perlでもハッシュを使うことができる。

1つ目は、'key1'から'key3'までをキーとして、'value1'から'value3'までを値として、ハッシュにセットした後、そのハッシュに各キーを指定して、値を取得し、出力。
2つ目は、リストでキーと値の関係を指定。
この場合、0番目、2番目、4番目がキーとなり、1番目、3番目、5番目が値となる。
3つ目は、リストで"=>"を使う場合の指定。
これは直感的でいい。

$ perl hash.pl
value1
value2
value3
valuea
valueb
valuec
valuex
valuey
valuez
$

このように、ハッシュの指定されたキーに対する値を出力できた。

Sample/perl/hash/hash/src/hash at master · bg1bgst333/Sample · GitHub

PolyBezierTo

PolyBezierToで、ベジェ曲線を描画できる。

PolyBezierTo function (wingdi.h) | Microsoft Docs
ベジェ曲線
ベジェ曲線を手で描いてみる - にせねこメモ

ベジェ曲線の描き方とか理論とかはちょっと難しいので上の記事を参照。
PolyBezierTo.cppにおいて、WindowProcのWM_CREATE時に、

	// スタティック変数の宣言
	static POINT pt[3];	// ベジェ曲線の描画に必要な制御点pt.(要素数3.)

	// ウィンドウメッセージに対する処理.
	switch (uMsg) {	// switch-casa文でuMsgの値ごとに処理を振り分ける.

		// ウィンドウの作成が開始された時.
		case WM_CREATE:		// ウィンドウの作成が開始された時.(uMsgがWM_CREATEの時.)

			// WM_CREATEブロック
			{

				// ベジェ曲線の描画に必要な制御点の初期値をセット.
				pt[0].x = 200;	// pt[0]のX座標は200.
				pt[0].y = 150;	// pt[0]のY座標は150.
				pt[1].x = 300;	// pt[1]のX座標は300.
				pt[1].y = 200;	// pt[1]のY座標は200.
				pt[2].x = 400;	// pt[2]のX座標は400.
				pt[2].y = 250;	// pt[2]のY座標は250.

				// ウィンドウ作成成功
				return 0;	// return文で0を返して, ウィンドウ作成成功とする.

			}

			// 既定の処理へ向かう.
			break;	// breakで抜けて, 既定の処理(DefWindowProc)へ向かう.

まずは、こんな感じで1つの直線上に制御点が通るようにセットしておく。
WM_PAINTで、

開始の制御点も(100, 100)で、これで(100, 100)-(400, 250)の直線上を通るようになっている。
これで実行すると、

ベジェ曲線どころか直線
ベジェ曲線どころか直線

ベジェ曲線どころか直線になってしまう。
そこで、

pt[0]の座標がより左下、pt[1]の座標がより右上に来るように、制御点を修正すると、

S字に曲がるようになった
S字に曲がるようになった

S字に曲がるようになった。
ベジェ曲線っぽいね。

Sample/winapi/PolyBezierTo/PolyBezierTo/src/PolyBezierTo at master · bg1bgst333/Sample · GitHub

配列スライス

配列スライスという、複数の添字を指定できる方法を使って、配列の複数の要素から値を取り出したり、逆に複数の要素に値を代入することができる。

配列スライス - Perl入門ゼミ

@ary1の0番目と2から4番目までを@ary2に代入し、それぞれの値を出力。
その後に、今度は@ary3の0番目と4番目に文字列を代入し、出力。

$ vi array.pl
$ perl array.pl
$var = ABC
$var = GHI
$var = JKL
$var = MNO
$var = AAA
$var =
$var =
$var =
$var = EEE
$

こうなる。

Sample/perl/array/array_slices/src/array at master · bg1bgst333/Sample · GitHub

split

splitは指定されたパターンで文字列を分割する。

split関数 - 文字列 - Perl関数のリファレンス

正規表現で複雑なパターンを指定できる。

正規表現が少し難しいがこんな感じ。
カンマ、もしくは、連続する空白類で区切るのだが、カンマの前後に空白が入っていた場合は、それも含めて1つの区切り文字列として処理する。

$ vi split.pl
$ perl split.pl
$var = ABC
$var = DEF
$var = GHI
$var = JKL
$var = MNO
$var = PQR
$var = STU
$

想定通りの区切りが出来た。

Sample/perl/split/split/src/split at master · bg1bgst333/Sample · GitHub