5分で読める自作シェルの作り方
シェルはユーザーからのコマンドを受け取り、それを実行するためのインターフェースです。LinuxやUnix系のOSで一般的に使用されるbashやzshなどが有名ですが、ここではC言語を使用して簡単な自作シェルを作る方法を解説します。この入門記事を通じて、シェルの基本的な構造と動作原理を理解し、自分だけのシェルを作成する第一歩を踏み出しましょう。
基本構成
自作シェルの開発には、以下のステップが含まれます:
- 入力の読み取り:ユーザーからの入力を受け取ります。
- コマンドの解析(パース):入力されたコマンドラインをコマンドとその引数に分割します。
- コマンドの実行:解析したコマンドを実行します。
- プロセスの終了を待つ:コマンドが外部プログラムである場合、その終了を待ちます。
- 繰り返し:ユーザーがシェルを終了するまで、上記のステップを繰り返します。
実装
入力の読み取り
char *read_line(void) {
char *line = NULL;
size_t bufsize = 0;
getline(&line, &bufsize, stdin);
return line;
}
コマンドの解析
char **split_line(char *line) {
int bufsize = 64, position = 0;
char **tokens = malloc(bufsize * sizeof(char*));
char *token;
token = strtok(line, " \t\r\n\a");
while (token != NULL) {
tokens[position++] = token;
token = strtok(NULL, " \t\r\n\a");
}
tokens[position] = NULL;
return tokens;
}
コマンドの実行
int execute(char **args) {
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0) {
if (execvp(args[0], args) == -1) {
perror("exec");
}
exit(EXIT_FAILURE);
} else if (pid < 0) {
perror("fork");
} else {
do {
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
メインループ
void loop(void) {
char *line;
char **args;
int status;
do {
printf("> ");
line = read_line();
args = split_line(line);
status = execute(args);
free(line);
free(args);
} while (status);
}
int main(void) {
loop();
return EXIT_SUCCESS;
}
使用例
- プログラムをコンパイルし、実行します
gcc -o myshell myshell.c && ./myshell
- プロンプトが表示されたら、各種コマンド(例:
ls
,cd directory_name
,cat file.txt
)を入力して実行します。ls => file1 dirA ...
まとめ
この記事では、C言語を用いて基本的な自作シェルを作成する方法を紹介しました。シェルプログラミングは、OSのプロセス管理やユーザーインターフェースの基礎を学ぶ絶好の機会です。ここで紹介したコードはシェルの基本的な骨組みを提供しますが、さらに高度な機能(リダイレクト、パイプライン、シグナルハンドリングなど)を追加することで、より強力で柔軟なシェルを開発することが可能です。