diff --git a/assignments/assignment-5/questions.md b/assignments/assignment-5/questions.md
index b4789bf92878bf1116e24c4c9ea28110d6d5f4e7..c5f3c7d0d98496ac795f0f60e92e8f01b8a72f17 100644
--- a/assignments/assignment-5/questions.md
+++ b/assignments/assignment-5/questions.md
@@ -1,15 +1,15 @@
 1. Your shell forks multiple child processes when executing piped commands. How does your implementation ensure that all child processes complete before the shell continues accepting user input? What would happen if you forgot to call waitpid() on all child processes?
 
-_answer here_
+_My implementation makes sure this doesn't happen by calling waitpid() on each child process after it has been forked. If I had forgot to do this, this may have led to zombie processes and resource leaks from the child because it won't terminate properly._
 
 2. The dup2() function is used to redirect input and output file descriptors. Explain why it is necessary to close unused pipe ends after calling dup2(). What could go wrong if you leave pipes open?
 
-_answer here_
+_It is necessary to close unused pipes to prevent resource leakage because if you don't, it will burn resources for no reason._
 
 3. Your shell recognizes built-in commands (cd, exit, dragon). Unlike external commands, built-in commands do not require execvp(). Why is cd implemented as a built-in rather than an external command? What challenges would arise if cd were implemented as an external process?
 
-_answer here_
+_If we were to treat cd as an external command, it would cd the child process instead of the parent, which means we basically wouldn't be cd'ing anything at all since when the child process terminates, the parent shell is still in the original directory._
 
 4. Currently, your shell supports a fixed number of piped commands (CMD_MAX). How would you modify your implementation to allow an arbitrary number of piped commands while still handling memory allocation efficiently? What trade-offs would you need to consider?
 
-_answer here_
+_I could modify my implementation by using dynamic lists instead of a fixed number. However, if we were to do that, we would potentially be needing a lot of memory if the person typing in the shell decides to put in a large number of commands constantly. This would also lead to some complexity within the code because you now would need to deal with your shell having to go through several more commands at once than what you might have built the shell for._
diff --git a/assignments/assignment-5/starter/bats/assignment_tests.sh b/assignments/assignment-5/starter/bats/assignment_tests.sh
old mode 100755
new mode 100644
diff --git a/assignments/assignment-5/starter/bats/student_tests.sh b/assignments/assignment-5/starter/bats/student_tests.sh
old mode 100755
new mode 100644
index 638bc341446f7580a80c2aff52971b8023407ea8..fdc56b3a09b6b070e497a2afb9d8474347b87ec0
--- a/assignments/assignment-5/starter/bats/student_tests.sh
+++ b/assignments/assignment-5/starter/bats/student_tests.sh
@@ -5,10 +5,84 @@
 # Create your unit tests suit in this file
 
 @test "Example: check ls runs without errors" {
-    run ./dsh <<EOF                
+    	run ./dsh <<EOF                
 ls
 EOF
 
-    # Assertions
-    [ "$status" -eq 0 ]
+    	# Assertions
+    	[ "$status" -eq 0 ]
+}
+
+@test "Exit Command works" {
+	run ./dsh <<EOF
+exit
+EOF
+    	# Assertions
+    	[ "$status" -eq 0 ]
+}
+
+@test "Multiple commands via pipes are run properly" {
+	run ./dsh <<EOF
+ls | ls
+exit
+EOF
+	# Assertions
+	[ "$status" -eq 0 ]
+}
+
+@test "No command is given" {
+	run ./dsh <<EOF
+
+exit
+EOF
+
+	# Strip all whitespace (spaces, tabs, newlines) from the output
+	stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+	# Expected output with all whitespace removed for easier matching
+	expected_output="dsh3>warning:nocommandsprovideddsh3>"
+
+	echo "Captured stdout:"
+	echo "Output: $stripped_output"
+	echo "Expected: $expected_output"
+	echo "Exit Status: $status"
+
+	# Check exact match
+	[ "$stripped_output" = "$expected_output" ]
+
+	# Assertions
+	[ "$status" -eq 0 ]
+}
+
+@test "Check if built in cd command works correctly" {
+	run ./dsh <<EOF
+cd ..
+pwd
+EOF
+	# Assertions
+	[ "$status" -eq 0 ]
+}
+
+@test "Check error handling for too many pipes" {
+	run ./dsh <<EOF
+ls | grep dshlib.c | grep armed | grep and | grep dangerous | grep again | grep again | grep again | grep again
+exit
+EOF
+
+        # Strip all whitespace (spaces, tabs, newlines) from the output
+        stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+        # Expected output with all whitespace removed for easier matching
+        expected_output="dsh3>error:pipinglimitedto8commandsdsh3>"
+
+        echo "Captured stdout:"
+        echo "Output: $stripped_output"
+        echo "Expected: $expected_output"
+        echo "Exit Status: $status"
+
+        # Check exact match
+        [ "$stripped_output" = "$expected_output" ]
+
+        # Assertions
+        [ "$status" -eq 0 ]
 }
diff --git a/assignments/assignment-5/starter/dsh b/assignments/assignment-5/starter/dsh
index 122f476185ab42843e019abfc92ae7f91acb299d..d7d0c175eba2254a6950a18d144f42c2d0dc6a52 100755
Binary files a/assignments/assignment-5/starter/dsh and b/assignments/assignment-5/starter/dsh differ
diff --git a/assignments/assignment-5/starter/dshlib.c b/assignments/assignment-5/starter/dshlib.c
index df3d58964bc0d719dbf4ec907338562474fa91df..f24530c2487e5a6aad113cceb6a2d211afaedc0b 100644
--- a/assignments/assignment-5/starter/dshlib.c
+++ b/assignments/assignment-5/starter/dshlib.c
@@ -150,193 +150,60 @@ int build_cmd_list(char *cmd_line, command_list_t *clist) {
 	return OK;
 }
 
-/*
-int exec_cmd(cmd_buff_t *cmd, int cmd_index, command_list_t *clist) {
-	int pipe_fds[2];
-	pid_t pid;
-
-	int is_last_cmd = (cmd_index == clist->num - 1);
-
-	printf("Command %d: is_last_cmd = %d\n", cmd_index, is_last_cmd);
-
-	if(!is_last_cmd) {
-		if(pipe(pipe_fds) == -1) {
-			perror("Pipe failed");
-			return -1;
-		}
-
-		printf("Command %d: Pipe created with fd[0] = %d, fd[1] = %d\n", cmd_index, pipe_fds[0], pipe_fds[1]);
+int exec_cmd(cmd_buff_t *cmd, int cmd_index, command_list_t *clist, int pipefd_in) {
+	int pipefd[2];
+	if(pipe(pipefd) == -1) {
+		perror("pipe");
+		exit(EXIT_FAILURE);
 	}
 
-	pid = fork();
-
+	pid_t pid = fork();
 	if(pid == -1) {
-		perror("Fork failed");
-		return -1;
+		perror("fork");
+		exit(EXIT_FAILURE);
 	}
 
 	if(pid == 0) {
-		printf("Command %d: Before redirecting, STDOUT_FILENO = %d\n", cmd_index, STDOUT_FILENO);
-		
-		// Debug: Print the arguments for execvp to check if the command is correct
-        	printf("Command %d: execvp arguments:\n", cmd_index);
-        	for (int i = 0; cmd->argv[i] != NULL; i++) {
-            		printf("argv[%d]: '%s'\n", i, cmd->argv[i]);
-        	}
-
-		// Ensure stdin redirection for the second command
-                if (cmd_index > 0) {
-                        if (dup2(clist->pipes[cmd_index - 1][0], STDIN_FILENO) == -1) {
-                                perror("Failed to redirect stdin");
-                                exit(1);
-                        }
-                        printf("Command %d: stdin redirected from pipe[%d][0] to STDIN_FILENO\n", cmd_index, cmd_index - 1);
-			close(clist->pipes[cmd_index - 1][0]);
-			printf("Command %d: Closed pipe[%d][0] in child process\n", cmd_index, cmd_index - 1);
-                }
-
-		// Redirect stdout if it's not the last command
-    		if (!is_last_cmd) {
-        		if (dup2(pipe_fds[1], STDOUT_FILENO) == -1) {
-            			perror("Failed to redirect stdout");
-            			exit(1);
-        		}
-        		printf("Command %d: stdout redirected to pipe[%d][1] from STDOUT_FILENO\n", cmd_index, cmd_index);
-			//close(pipe_fds[1]); // Close the write end of the pipe
-            		//printf("Command %d: Closed pipe[%d][1] in child process\n", cmd_index, cmd_index);
-    		}
-
-		for(int i = 0; i < clist->num - 1; i++) {
-            		if (i != cmd_index - 1) { // Don't close the pipe we're reading from
-                		close(clist->pipes[i][0]);
-                		close(clist->pipes[i][1]);
-                		printf("Command %d: Closed clist->pipes[%d][0] and clist->pipes[%d][1] in child process\n", cmd_index, i, i);   
-            		}
-        	}
-
-		close(pipe_fds[1]);
-
-		if(execvp(cmd->argv[0], cmd->argv) == -1) {
-			perror("Execvp failed");
-			exit(1);
+		if(cmd_index > 0) {
+			close(pipefd[0]);
 		}
-	}
-	else {
-		if(!is_last_cmd) {
-			close(pipe_fds[1]);
-			printf("Command %d: Parent closing write end pipe[%d][1]\n", cmd_index, cmd_index);
-			//close(pipe_fds[0]);
-			//printf("Command %d: Parent closing read end pipe[%d][0]\n", cmd_index, cmd_index);
+
+		if(cmd_index < clist->num - 1) {
+			close(pipefd[0]);
 		}
 
 		if(cmd_index > 0) {
-			close(clist->pipes[cmd_index - 1][0]);
-			printf("Command %d: Parent closing pipe[%d][0]\n", cmd_index, cmd_index - 1);
+			dup2(pipefd_in, STDIN_FILENO);
+			close(pipefd_in);
+		}
+
+		if(cmd_index < clist->num - 1) {
+			close(STDOUT_FILENO);
+			dup2(pipefd[1], STDOUT_FILENO);
+			close(pipefd[1]);
 		}
 
-		int status;
-		waitpid(pid, &status, 0);
-		printf("Command %d: Child process finished with status %d\n", cmd_index, status);
+		execvp(cmd->argv[0], cmd->argv);
+
+		perror("execvp");
+		exit(EXIT_FAILURE);
 	}
-	return OK;
-}
+	else {
+		close(pipefd[1]);
 
-*/
-
-int exec_cmd(cmd_buff_t *cmd, int cmd_index, command_list_t *clist) {
-    int pipe_fds[2];
-    pid_t pid;
-
-    int is_last_cmd = (cmd_index == clist->num - 1);
-
-    printf("Command %d: is_last_cmd = %d\n", cmd_index, is_last_cmd);
-
-    // Create pipe for non-last commands
-    if (!is_last_cmd) {
-        if (pipe(pipe_fds) == -1) {
-            perror("Pipe failed");
-            return -1;
-        }
-        printf("Command %d: Pipe created with fd[0] = %d, fd[1] = %d\n", cmd_index, pipe_fds[0], pipe_fds[1]);
-    }
-
-    pid = fork();
-
-    if (pid == -1) {
-        perror("Fork failed");
-        return -1;
-    }
-
-    if (pid == 0) { // Child process
-        printf("Command %d: Before redirecting, STDOUT_FILENO = %d\n", cmd_index, STDOUT_FILENO);
-
-	printf("Debug: Command %d, before redirecting, pipe_fds[1] = %d\n", cmd_index, pipe_fds[1]);
-
-        // Debug: Print the arguments for execvp to check if the command is correct
-        printf("Command %d: execvp arguments:\n", cmd_index);
-        for (int i = 0; cmd->argv[i] != NULL; i++) {
-            printf("argv[%d]: '%s'\n", i, cmd->argv[i]);
-        }
-
-        // Redirect input from previous command, if it's not the first command
-        if (cmd_index > 0) {
-            if (dup2(clist->pipes[cmd_index - 1][0], STDIN_FILENO) == -1) {
-                perror("Failed to redirect stdin");
-                exit(1);
-            }
-            printf("Command %d: stdin redirected from pipe[%d][0] to STDIN_FILENO\n", cmd_index, cmd_index - 1);
-            close(clist->pipes[cmd_index - 1][0]); // Close the read end of the previous pipe
-            printf("Command %d: Closed pipe[%d][0] in child process\n", cmd_index, cmd_index - 1);
-        }
-
-        // Redirect stdout to the pipe if this is not the last command
-        if (!is_last_cmd) {
-            if (dup2(pipe_fds[1], STDOUT_FILENO) == -1) {
-                perror("Failed to redirect stdout");
-                exit(1);
-            }
-            printf("Command %d: stdout redirected to pipe[%d][1] from STDOUT_FILENO\n", cmd_index, cmd_index);
-            close(pipe_fds[1]); // Close the write end of the pipe after redirection
-            printf("Command %d: Closed pipe[%d][1] in child process\n", cmd_index, cmd_index);
-        }
-
-        // Close all unnecessary file descriptors in child process
-        for (int i = 0; i < clist->num - 1; i++) {
-            if (i != cmd_index - 1) { // Don't close the pipe we're reading from
-                close(clist->pipes[i][0]);
-                close(clist->pipes[i][1]);
-                printf("Command %d: Closed clist->pipes[%d][0] and clist->pipes[%d][1] in child process\n", cmd_index, i, i);
-            }
-        }
-
-        // Execute the command
-        if (execvp(cmd->argv[0], cmd->argv) == -1) {
-            perror("Execvp failed");
-	    printf("Debug: Execvp failed for command %d. Pipe fds: pipe_fds[0] = %d, pipe_fds[1] = %d\n", cmd_index, pipe_fds[0], pipe_fds[1]);
-            exit(1);
-        }
-    } else { // Parent process
-        // Close the write end of the pipe in the parent if it's not the last command
-        if (!is_last_cmd) {
-            close(pipe_fds[1]); // Parent closes the write end of the pipe
-            printf("Command %d: Parent closing write end pipe[%d][1]\n", cmd_index, cmd_index);
-        }
-
-        // Close the read end of the previous pipe in the parent process
-        if (cmd_index > 0) {
-            close(clist->pipes[cmd_index - 1][0]); // Parent closes the previous read end
-            printf("Command %d: Parent closing pipe[%d][0]\n", cmd_index, cmd_index - 1);
-        }
-
-        // Wait for the child process to finish
-        int status;
-        waitpid(pid, &status, 0);
-        printf("Command %d: Child process finished with status %d\n", cmd_index, status);
-    }
-    return OK;
+		if(cmd_index < clist->num - 1) {
+			int next_pipefd = pipefd[0];
+			waitpid(pid, NULL, 0);
+			return next_pipefd;
+		}
+		else {
+			waitpid(pid, NULL, 0);
+			close(pipefd[0]);
+			return -1;
+		}
+	}
 }
 
-
 int exec_local_cmd_loop() {
 
 	char *cmd_buff = malloc(SH_CMD_MAX * sizeof(char));
@@ -382,9 +249,10 @@ int exec_local_cmd_loop() {
 
 		switch(rc) {
 			case OK:
+				int pipefd_in = -1;
 				for(int i = 0; i < clist.num; i++) {
 					if(exec_built_in_cmd(&clist.commands[i]) == BI_NOT_BI) {
-						exec_cmd(&clist.commands[i], i, &clist);
+						pipefd_in = exec_cmd(&clist.commands[i], i, &clist, pipefd_in);
 					}
 				}
 				break;
diff --git a/assignments/assignment-5/starter/dshlib.h b/assignments/assignment-5/starter/dshlib.h
index c401a16ee46bedab9d21016cd58ce3eafa02b795..47d87e7a035f81b74da82f77674e2a8491ec34f0 100644
--- a/assignments/assignment-5/starter/dshlib.h
+++ b/assignments/assignment-5/starter/dshlib.h
@@ -80,7 +80,7 @@ Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd);
 
 //main execution context
 int exec_local_cmd_loop();
-int exec_cmd(cmd_buff_t *cmd, int cmd_index, command_list_t *clist);
+int exec_cmd(cmd_buff_t *cmd, int cmd_index, command_list_t *clist, int pipefd_in);
 int execute_pipeline(command_list_t *clist);
 
 
diff --git a/assignments/assignment-5/starter/output.txt b/assignments/assignment-5/starter/output.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d46f5ff9bbc9f842450c3b400b3b286fb84f50e9
--- /dev/null
+++ b/assignments/assignment-5/starter/output.txt
@@ -0,0 +1,2 @@
+Output of first command:
+whoami