C言語でcatコマンドを書きたい

■要求定義
– ファイルの内容を表示する

■検討
– ファイルの中身を1行ずつ表示したい
– ファイルの1行を何バイトにするか?

#include <stdio.h>

int main(){

	FILE *fp;
	char str[1024];

	fp = fopen("hello.c","r");

	if(fp == NULL){
		printf("failed.\n");
		return -1;
	}

	while((fgets(str,256,fp)) !=NULL){
		printf("%s", str);
	}
	fclose(fp);

	return 0;
}

$ ./dev
#include

int main(){

FILE *fp;
char str[1024];

fp = fopen(“hello.c”,”r”);

if(fp == NULL){
printf(“failed.\n”);
return -1;
}

while((fgets(str,256,fp)) !=NULL){
printf(“%s”, str);
}
fclose(fp);

return 0;
}

PHPのfgets()だと、lengthが指定されない場合、1024バイト上限だから、fgets(str,256,fp)もfgets(str,1024,fp)の方が良いのかな。
しかし、C言語勉強していると、他の言語との互換性を強く感じられるな。

C言語でfindコマンドを書きたい

■要求定義
– ファイルの検索をする

■検討
– ファイルがあった時
-> ファイル名をそのまま返す
$ ls
dev hello.c
$ find hello.c
hello.c

– ファイルが無かった時
-> エラーメッセージを表示する
$ find test.dat
find: ‘test.dat’: No such file or directory

– fopenとstat(非標準)を使う方法がある

fopenで存在確認

int main(){

	FILE *fp = "hoge.c";
	if(fopen(fp, "r") == NULL) {
		printf("'%s': No such file or directory\n", fp);
	} else {
		printf("%s\n", fp);
	}

	return 0;
}

$ ./dev
‘hogehoge.c’: No such file or directory

メッセージをlinuxに合わせると雰囲気を出せる。

#include <stdio.h>
#include <sys/stat.h> // ファイル・ディレクトリに関する情報取得


int main(){

	struct stat st; 
	FILE *fp = "hogehoge.c";
	if(stat(fp, &st) != 0) {
		printf("'%s': No such file or directory\n", fp);
	} else {
		printf("%s\n", fp);
	}

	return 0;
}

$ ./dev
‘hogehoge.c’: No such file or directory

成功すると 0 を、エラー発生時には -1を返す。
非標準なので、statよりもfopenか。

返り値が0 | 1 ってのが、2進数を扱っている実感ができて良い。

C言語でpwdコマンドを書きたい

■要求定義
– 現在いる位置を表示する

■考察
-getcwd()のカレントディレクトリ取得を使う

#include <stdio.h>


int main(){

	char pathname[256];
	getcwd(pathname, 256);
	printf("%s\n", pathname);

	return 0;
}

$ ./dev
/home/vagrant/dev

これは何も考える事ないです。

C言語でrmコマンドを書きたい

■要求定義
– ファイルやフォルダを削除する
– リクルーシブの削除も対応したい

■考えた事
– remove()と_unlink()があるらしい
– remove関数は、厳密には「その名前でのファイルへのアクセスを、再びファイルを生成しない限り、不可能にする」という処理を行なっているらしい

int main(){

	// char *dir = "./newfolder";
	char *dir = "./hoge.txt";
	if(remove(dir) == 0){
		printf("%sの削除が完了しました。\n", dir);
	} else {
		printf("%sの削除に失敗しました。\n", dir);
	}
	return 0;
}

$ ./dev
./hoge.txtの削除が完了しました。

*dirをファイルがあるフォルダに変更するとremoveでは削除できない
$ ./dev
./newfolderの削除に失敗しました。

->ディレクトリ内のファイルを削除してからディレクトリを削除するというステップが必要

■フォルダの中のファイルリスト一覧表示

#include <stdio.h>
#include <dirent.h>

int main(){

	DIR *dir;
	struct dirent *dp;
	char dirpath[] = "./newfolder";

	dir = opendir(dirpath);
	if(dir == NULL) { return 1; }

	dp = readdir(dir);
	while(dp != NULL){
		printf("%s\n", dp->d_name);
		dp = readdir(dir);
	}

	if(dir != NULL) {
		closedir(dir);
	}
	return 0;
}

$ ./dev
.
foo.c
..
hoge.c

これをremove()と組み合わせれば再帰的に削除できるか。

#include <stdio.h>
#include <string.h>
#include <dirent.h>

int main(){

	DIR *dir;
	char newdir[255] = "./newfolder/";

	char *target = "./newfolder";
	if(remove(target) == 0){
		printf("%sの削除が完了しました。\n", target);
	} else {

		struct dirent *dp;
		dir = opendir(target);
		if(dir == NULL) { return 1; }

		dp = readdir(dir);
		while(dp != NULL){
			// printf("%s\n", dp->d_name);
			strcat(newdir,dp->d_name);
			printf("%s\n", newdir);
			remove(newdir);
			dp = readdir(dir);
		}
		if(dir != NULL) {
			closedir(dir);
		}
		remove(target);
		printf("%sの削除が完了!\n", target);
	}

	
	return 0;
}

$ ./dev
./newfolder/.
./newfolder/.foo.c
./newfolder/.foo.c..
./newfolder/.foo.c..hoge.c
./newfolderの削除が完了!

strcatで文字列連結するのがうまくいってない。何故だろう。

C言語でrmdirコマンドを書きたい

■要求定義
– 空のフォルダを削除する

#include <stdio.h>
#include <sys/stat.h>

int main(){

	char *dir = "./newfolder";
	rmdir(dir);
		
	return 0;
}

$ ./dev

フォルダの中にファイルが入っているときは、rmdirでは削除されない。

linuxコマンドとcの標準ライブラリ関数がネーミングが同じ場合は面白みがないな。

C言語でtouchコマンドを書きたい

■要求定義
– ファイルを作成する

■検討
– touchはファイルの中身は書かないから、fopen, fcloseだけで良いか?

#include <stdio.h>

int main(){

	FILE *fp;
	fp = fopen("test.txt", "w");
	fclose(fp);
		
	return 0;
}

$ ./dev

■追加
– コマンドラインで入力した値のファイルを作成する

#include <stdio.h>

int main(){

	char ss[256];
    gets(ss);

	FILE *fp;
	fp = fopen(ss, "w");
	fclose(fp);
		
	return 0;
}

$ ./dev
hoge.txt

できました。

fopenの拡張子はテキストファイル(.dat, .txt, .c, .h)、バイナリファイル(.exe, .jpg, .gif, .mpeg)どちらも可

なるほど、C言語はバイナリの概念がかなり出てくるな。。

C言語でclearコマンドを書きたい

■要求定義
– 消さずに画面を綺麗にする

■検討
– windowsでsystem(“cls”); で消せると書いてある。嫌な予感がするが、bionicでも動く?

#include 
#include 

int main(){

	for(int idx=0; idx<10; idx++){
    	printf("%d\n", idx);
  	}

	system("clear");
		
	return 0;
}

0
1
2
3
4
5
6
7
8
9
sh: 1: cls: not found

やっぱり。DOS/Windowsコマンドらしく、linuxには無いとのこと。

int main(){

	for(int idx=0; idx<10; idx++){
    	printf("%d\n", idx);
  	}

	system("clear");
		
	return 0;
}

これなら動くけど意味ないね。

エスケープシーケンシーとはターミナルを制御する制御文字
printf("\033[2J") //画面クリア
などがある。

system("\033[2J");


う〜ん、clearコマンドとはちょっと違うな。

C言語でcpコマンドを書きたい

■要求定義
– ファイルやフォルダをコピーする
– cp (移動元ファイル名/フォルダ名) (移動先ファイル名/フォルダ名) 

#include <stdio.h>
#include <stdlib.h> //汎用ライブラリ
#include <string.h>

int main(){

	FILE *fpSrc, *fpDes, *fp;
	char ss[256], ch[50];

	fpSrc = fopen("test.txt", "r");
	fpDes = fopen("copy.txt", "w");

	while(fgets(&ss, 256, fpSrc) != NULL){
		printf("%s", ss);
		fwrite(ss, 1, 8, fpDes);
	}

	fclose(fpSrc);
	fclose(fpDes);

	printf("コピーしました。\n");
		
	return 0;
}

$ ./dev
asdf
1234コピーしました。

■考察
あれ、コピー先のデータはバイナリデータで入ってるな。
調べてみると、fwriteはバイナリデータの書き込みとのこと。
fwriteではなく、fputs()に変更します。

int main(){

	FILE *fpSrc, *fpDes;
	char ss[256];

	fpSrc = fopen("test.txt", "r");
	fpDes = fopen("copy.txt", "w");

	while(fgets(&ss, 256, fpSrc) != NULL){
		printf("%s", ss);
		fputs(ss, fpDes);
	}

	fclose(fpSrc);
	fclose(fpDes);

	printf("コピーしました。\n");
		
	return 0;
}

コピーできました。
バイナリとは2進数データのこと。

C言語でmvコマンドを書きたい

■要求定義
– ファイルを移動させる

■ステップ1
– 標準ライブラリ関数であるrename関数を使う

#include <stdio.h>

int main(){

	rename("./test.c", "./hoge/test.c");
	printf("移動しました。\n");
		
	return 0;
}

$ ./dev
移動しました。

移動できた事を確認。

■ステップ2
– ユーザ入力で$ mv ${FileName} ${MoveDir}となるので、コマンドラインからの入力を元に移動させたい
– 文字列の分割は”strtok”を使う。ポインタでファイル名s1, 異動先s2を指定する。

#include <stdio.h>
#include <string.h>

int main(){

	char ss[256] = "./test.c ./hoge/test.c";
	char *s1, *s2;
	s1 = strtok(ss, " ");
	s2 = strtok(NULL, " ");
	rename(s1, s2);	
	printf("移動しました。\n");
		
	return 0;
}

■ステップ3
– gets()でコマンドラインから入力した値を取得して移動させたい

int main(){

	// char ss[256] = "./test.c ./hoge/test.c";
	char ss[256];
	char *s1, *s2;
	
	gets(ss);
	s1 = strtok(ss, " ");
	s2 = strtok(NULL, " ");
	rename(s1, s2);	
	printf("移動しました。\n");
		
	return 0;
}

$ ./dev
./test.c ./hoge/test.c
移動しました。

ほう、面白い。コマンドラインからの入力は、strtokで分割して処理すれば良いですな。