diff --git a/include/commands.h b/include/commands.h
index 84355e20c28ea7db7cb2edc74add1e08e711b89a..7fbe4d9777458b930b91719f6bceeaff6156fa80 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -7,4 +7,8 @@ struct single_command
   char** argv;
 };
 
+int evaluate_command(int n_commands, struct single_command (*commands)[]);
+
+void free_commands(int n_commands, struct single_command (*commands)[]);
+
 #endif // MYSH_COMMANDS_H_
diff --git a/src/built_in.c b/src/built_in.c
index 5c7964915cadc5784ee73cff8053bc9a9424899d..9a466e91501d5877107fb67e308275c4847bcb38 100644
--- a/src/built_in.c
+++ b/src/built_in.c
@@ -61,7 +61,7 @@ int validate_pwd_argv(int argc, char** argv) {
 }
 
 int validate_fg_argv(int argc, char** argv) {
-  if (argv != 1) return 0;
+  if (argc != 1) return 0;
   if (strcmp(argv[0], "fg") != 0) return 0;
   
   return 1;
diff --git a/src/commands.c b/src/commands.c
index ef5f4b9ca3b9370c093edc42bb1450821227214d..2a4e6eccf7c1efd74825114ee6b2f08894d0fc96 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1,10 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
 #include "commands.h"
 #include "built_in.h"
 
-struct built_in_command built_in_commands[] = {
+static struct built_in_command built_in_commands[] = {
   { "cd", do_cd, validate_cd_argv },
   { "pwd", do_pwd, validate_pwd_argv },
   { "fg", do_fg, validate_fg_argv }
 };
 
+static int is_built_in_command(const char* command_name)
+{
+  static const int n_built_in_commands = sizeof(built_in_commands) / sizeof(built_in_commands[0]);
+
+  for (int i = 0; i < n_built_in_commands; ++i) {
+    if (strcmp(command_name, built_in_commands[i].command_name) == 0) {
+      return i;
+    }
+  }
+
+  return -1; // Not found
+}
+
+/*
+ * Description: Currently this function only handles single built_in commands. You should modify this structure to launch process and offer pipeline functionality.
+ */
+int evaluate_command(int n_commands, struct single_command (*commands)[])
+{
+  if (n_commands > 0) {
+    struct single_command* com = (*commands);
+
+    assert(com->argc != 0);
+
+    int built_in_pos = is_built_in_command(com->argv[0]);
+    if (built_in_pos != -1) {
+      if (built_in_commands[built_in_pos].command_validate(com->argc, com->argv)) {
+        if (built_in_commands[built_in_pos].command_do(com->argc, com->argv) != 0) {
+          fprintf(stderr, "%s: Error occurs\n", com->argv[0]);
+        }
+      } else {
+        fprintf(stderr, "%s: Invalid arguments\n", com->argv[0]);
+        return -1;
+      }
+    } else if (strcmp(com->argv[0], "") == 0) {
+      return 0;
+    } else if (strcmp(com->argv[0], "exit") == 0) {
+      return 1;
+    } else {
+      fprintf(stderr, "%s: command not found\n", com->argv[0]);
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+void free_commands(int n_commands, struct single_command (*commands)[])
+{
+  for (int i = 0; i < n_commands; ++i) {
+    struct single_command *com = (*commands) + i;
+    int argc = com->argc;
+    char** argv = com->argv;
+
+    for (int j = 0; j < argc; ++j) {
+      free(argv[j]);
+    }
+
+    free(argv);
+  }
 
+  memset((*commands), 0, sizeof(struct single_command) * n_commands);
+}
diff --git a/src/main.c b/src/main.c
index 18697a3e73f4e97b6f5449f25df348c2eac92418..77c78049273e013e278ad9021fa088531b636a97 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,40 +17,14 @@ int main()
     int n_commands = 0;
     mysh_parse_command(buf, &n_commands, &commands);
 
-    for (int i = 0; i < n_commands; ++i) {
-      struct single_command* com = commands + i;
-      int argc = com->argc;
-      char** argv = com->argv;
-      for (int j = 0; j < argc; ++j) {
-        printf("%s ", argv[j]);
-      }
-      printf("\n");
-    }
+    int ret = evaluate_command(n_commands, &commands);
+
+    free_commands(n_commands, &commands);
+    n_commands = 0;
 
-    /*
-
-    if (strcmp(argv[0], "") == 0) {
-      goto release_and_continue;
-    } else if (strcmp(argv[0], "cd") == 0) {
-      if (do_cd(argc, argv)) {
-        fprintf(stderr, "cd: Invalid arguments\n");
-      }
-    } else if (strcmp(argv[0], "pwd") == 0) {
-      if (do_pwd(argc, argv)) {
-        fprintf(stderr, "pwd: Invalid arguments\n");
-      }
-    } else if (strcmp(argv[0], "exit") == 0) {
-      goto release_and_exit;
-    } else {
-      fprintf(stderr, "%s: command not found\n", argv[0]);
+    if (ret == 1) {
+      break;
     }
-release_and_continue:
-    release_argv(argc, &argv);
-    continue;
-release_and_exit:
-    release_argv(argc, &argv);
-    break;
-    */
   }
 
   return 0;
diff --git a/src/utils.c b/src/utils.c
index 75958f46eb3d95cb3fa882711508a80dd18a51df..6fbc970d8bb0840c88240f73cdc330414d4cd680 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -33,6 +33,8 @@ void parse_single_command(const char* command,
 {
   const int kMaxArgc = 512;
   *argv = (char**)malloc(kMaxArgc * sizeof(char*));
+  for (int i = 0; i < kMaxArgc; ++i)
+    (*argv)[i] = NULL;
 
   char buf[4096];
   strcpy(buf, command);