From 17501b59b41f5ff814fa14ac2de798b246135201 Mon Sep 17 00:00:00 2001 From: Aleksandr Lebedev Date: Tue, 21 Apr 2026 02:51:59 +0200 Subject: [PATCH 1/2] Redirrect support for >, >>, <, &>, 2> - cd does less work now --- main.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/main.c b/main.c index 95c60ee..c24db11 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,7 @@ #include #include #include +#include constexpr size_t max_length = 1024; constexpr size_t max_env_var_length = 256; @@ -86,7 +87,7 @@ struct command * IO redirections; redirect[i] should be used as fd i in the child. * A value of -1 indicates no redirect. */ - int redirect[2]; + int redirect[3]; /** The arguments; must be NULL-terminated. */ char* argv[]; }; @@ -358,6 +359,13 @@ char* parse_token(char** input) return buf; } +int open_fout(const char* file, bool append) +{ + return open(file, + O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), + 0644); +} + /** * Parses str into a freshly allocated command struct and returns a pointer to it. * The redirects in the returned command will be set to -1, ie no redirect. @@ -378,6 +386,8 @@ struct command* parse_command(char* str) struct command* ret = ccalloc(sizeof(struct command) + strlen(copy) * sizeof(char*), 1); parser_allocated(ret); + ret->redirect[0] = ret->redirect[1] = ret->redirect[2] = -1; + char* p = copy; while (*p) @@ -387,9 +397,47 @@ struct command* parse_command(char* str) if (!token) break; + if (strcmp(token, ">") == 0) + { + char* file = parse_token(&p); + int fd = open_fout(file, false); + ret->redirect[STDOUT_FILENO] = fd; + continue; + } + if (strcmp(token, ">>") == 0) + { + char* file = parse_token(&p); + int fd = open_fout(file, true); + ret->redirect[STDOUT_FILENO] = fd; + continue; + } + if (strcmp(token, "<") == 0) + { + char* file = parse_token(&p); + int fd = open(file, O_RDONLY); + ret->redirect[STDIN_FILENO] = fd; + continue; + } + + if (strcmp(token, "2>") == 0) + { + char* file = parse_token(&p); + int fd = open_fout(file, false); + ret->redirect[STDERR_FILENO] = fd; + continue; + } + + if (strcmp(token, "&>") == 0) + { + char* file = parse_token(&p); + int fd = open_fout(file, false); + ret->redirect[STDOUT_FILENO] = fd; + ret->redirect[STDERR_FILENO] = fd; + continue; + } + ret->argv[i++] = token; } - ret->redirect[0] = ret->redirect[1] = -1; return ret; } @@ -495,15 +543,17 @@ void close_ALL_the_pipes(int n_pipes, int (*pipes)[2]) int exec_with_redir(struct command* command, int n_pipes, int (*pipes)[2]) { - int fd = -1; - if ((fd = command->redirect[0]) != -1) + void apply_redir(int fd, int target) { - dup2(fd, STDIN_FILENO); - } - if ((fd = command->redirect[1]) != -1) - { - dup2(fd, STDOUT_FILENO); + if (fd != -1) + { + dup2(fd, target); + if (fd > 2) close(fd); //if file + } } + apply_redir(command->redirect[0], STDIN_FILENO); + apply_redir(command->redirect[1], STDOUT_FILENO); + apply_redir(command->redirect[2], STDERR_FILENO); close_ALL_the_pipes(n_pipes, pipes); return execvp(command_name(command), command->argv); } @@ -536,6 +586,10 @@ pid_t run_with_redir(struct command* command, int n_pipes, int (*pipes)[2]) int cd(char* path) { int result = chdir(path); + if(result < 0) + { + return result; + } char cwd[max_length]; if (getcwd(cwd, sizeof(cwd)) != NULL) { From 8285e148e170b4b6b3e89b98c1747171b65be1a4 Mon Sep 17 00:00:00 2001 From: Aleksandr Lebedev Date: Tue, 21 Apr 2026 02:56:05 +0200 Subject: [PATCH 2/2] Updated README --- README.org | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.org b/README.org index cb51201..4515796 100644 --- a/README.org +++ b/README.org @@ -4,7 +4,9 @@ Simple shell for Unix-like systems written in C, that has a funny name (for germ * Features - Can run commands - You can pipe stdout of one command to stdin of another (ex. ~cat main.c | wc --lines~) +- Your can redirrect output/input with ~>~, ~>>~, ~<~, ~2>~, ~&>~ - Variables expansion with ~$PATH~ and ~${HOME}~ syntax +- Shows custom prompt, if ~PS1~ env variable is set - Run subcomands with ~$(hostname)~ or ~`pwd`~ (works with pipes) - ~cd~ builtin command (~cd~ without arguments moves you to ~$HOME~) - ~exit~ builtin command