diff --git a/README.md b/README.md
index 8a25fdd04c7dbf460b38556e392281ffde06cf69..1734067266288e7d278082e4bb79595c7ec75e86 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,7 @@ The `let` keyword is utilized to create local variables within the shell. The `e
 a similar action, only setting the variable globally as an environment variable for the operating system.
 
 ```ion
-// TODO: Ion Shell does not yet implement stderr redirection.
-let git_branch = $(git rev-parse --abbrev-ref HEAD 2> /dev/null)
+let git_branch = $(git rev-parse --abbrev-ref HEAD ^> /dev/null)
 ```
 
 If the command is executed without any arguments, it will simply list all available variables.
@@ -196,4 +195,4 @@ end
 for i in 1..20
     fib $i
 end
-```
\ No newline at end of file
+```
diff --git a/src/parser/peg.rs b/src/parser/peg.rs
index 184e4d17d89f11782bdb871407f0ae2ca0f85160..d957e804ba462e743d0f04905a25641253cbf9f4 100644
--- a/src/parser/peg.rs
+++ b/src/parser/peg.rs
@@ -6,7 +6,7 @@ use self::grammar::parse_;
 
 use glob::glob;
 
-#[derive(Debug, PartialEq, Clone)]
+#[derive(Debug, PartialEq, Clone, Copy)]
 pub enum RedirectFrom { Stdout, Stderr, Both}
 
 #[derive(Debug, PartialEq, Clone)]
diff --git a/src/parser/pipelines.rs b/src/parser/pipelines.rs
index 1d17da388ae77eeb1b6496c85897d76ecaa531f1..fa5777b469dd949b6d50b848324595129c3bc6da 100644
--- a/src/parser/pipelines.rs
+++ b/src/parser/pipelines.rs
@@ -1,7 +1,6 @@
 // TODO:
 // - Implement Herestrings
 // - Implement Heredocs
-// - Implement Stderr Redirection
 // - Implement Stderr Piping
 // - Fix the cyclomatic complexity issue
 
@@ -21,7 +20,7 @@ const PROCESS_VAL:  u8 = 255 ^ (BACKSLASH + WHITESPACE + 32);
 const IS_VALID: u8 = 255 ^ (BACKSLASH + WHITESPACE);
 
 #[derive(PartialEq)]
-enum RedirMode { False, Stdin, Stdout, StdoutAppend }
+enum RedirMode { False, Stdin, Stdout(RedirectFrom), StdoutAppend(RedirectFrom) }
 
 fn get_job_kind(args: &str, index: usize, pipe_char_was_found: bool) -> (JobKind, bool) {
     if pipe_char_was_found {
@@ -41,7 +40,7 @@ fn get_job_kind(args: &str, index: usize, pipe_char_was_found: bool) -> (JobKind
 /// Parses each individual pipeline, separating arguments, pipes, background tasks, and redirections.
 pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>, args: &str) {
     let mut jobs: Vec<Job> = Vec::new();
-    let mut args_iter = args.bytes();
+    let mut args_iter = args.bytes().peekable();
     let (mut index, mut arg_start) = (0, 0);
     let mut flags = 0u8; // (backslash, single_quote, double_quote, x, x, x, process_one, process_two)
 
@@ -52,14 +51,14 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
     let mut levels = 0;
 
     macro_rules! redir_check {
-        ($file:ident, $name:ident, $is_append:expr) => {{
+        ($from:expr, $file:ident, $name:ident, $is_append:expr) => {{
             if $file.is_none() {
                 if $name.is_empty() {
                     *possible_error = Some("missing standard output file argument after '>'");
                 } else {
                     $file = Some(Redirection {
-                        from: RedirectFrom::Stdout,
-                        file: unsafe { String::from_utf8_unchecked($name) },
+                        from:   $from,
+                        file:   unsafe { String::from_utf8_unchecked($name) },
                         append: $is_append
                     });
                 }
@@ -125,8 +124,21 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                             }
                         },
                         b'|' if (flags & (255 ^ BACKSLASH) == 0) => job_found!(true),
-                        b'&' if (flags & IS_VALID == 0) => job_found!(false),
-                        b'>' if (flags & IS_VALID == 0) => redir_found!(RedirMode::Stdout),
+                        b'&' if (flags & (255 ^ BACKSLASH) == 0) => {
+                            if args_iter.peek() == Some(&b'>') {
+                                let _ = args_iter.next();
+                                redir_found!(RedirMode::Stdout(RedirectFrom::Both));
+                            } else {
+                                job_found!(false)
+                            }
+                        },
+                        b'^' if (flags & IS_VALID == 0) => {
+                            if args_iter.peek() == Some(&b'>') {
+                                let _ = args_iter.next();
+                                redir_found!(RedirMode::Stdout(RedirectFrom::Stderr));
+                            }
+                        },
+                        b'>' if (flags & IS_VALID == 0) => redir_found!(RedirMode::Stdout(RedirectFrom::Stdout)),
                         b'<' if (flags & IS_VALID == 0) => redir_found!(RedirMode::Stdin),
                         _   if (flags >> 6 != 2)        => flags &= 255 ^ (PROCESS_ONE + PROCESS_TWO),
                         _ => (),
@@ -135,9 +147,9 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                 }
                 break 'outer
             },
-            RedirMode::Stdout | RedirMode::StdoutAppend => {
+            RedirMode::Stdout(from) | RedirMode::StdoutAppend(from) => {
                 match args_iter.next() {
-                    Some(character) => if character == b'>' { mode = RedirMode::StdoutAppend; },
+                    Some(character) => if character == b'>' { mode = RedirMode::StdoutAppend(from); },
                     None => {
                         *possible_error = Some("missing standard output file argument after '>'");
                         break 'outer
@@ -169,7 +181,7 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                                 out_file = Some(Redirection {
                                     from: RedirectFrom::Stdout,
                                     file: unsafe { String::from_utf8_unchecked(stdout_file.clone()) },
-                                    append: mode == RedirMode::StdoutAppend
+                                    append: if let RedirMode::StdoutAppend(_) = mode { true } else { false }
                                 });
                             },
                             b'<' if stdout_file.is_empty() => {
@@ -180,7 +192,7 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                                 out_file = Some(Redirection {
                                     from: RedirectFrom::Stdout,
                                     file: unsafe { String::from_utf8_unchecked(stdout_file.clone()) },
-                                    append: mode == RedirMode::StdoutAppend
+                                    append: if let RedirMode::StdoutAppend(_) = mode { true } else { false }
                                 });
 
                                 if in_file.is_some() {
@@ -195,7 +207,12 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                     }
                 }
 
-                redir_check!(out_file, stdout_file, mode == RedirMode::StdoutAppend);
+                redir_check!(
+                    from,
+                    out_file,
+                    stdout_file,
+                    if let RedirMode::StdoutAppend(_) = mode { true } else { false }
+                );
 
                 break 'outer
             },
@@ -209,7 +226,7 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                             if out_file.is_some() {
                                 break 'outer
                             } else {
-                                mode = RedirMode::Stdout;
+                                mode = RedirMode::Stdout(RedirectFrom::Stdout);
                                 continue 'outer
                             }
                         }
@@ -252,7 +269,8 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
                     }
                 }
 
-                redir_check!(in_file, stdin_file, false);
+                let dummy_val = RedirectFrom::Stdout;
+                redir_check!(dummy_val, in_file, stdin_file, false);
 
                 break 'outer
             }
@@ -273,7 +291,26 @@ pub fn collect(pipelines: &mut Vec<Pipeline>, possible_error: &mut Option<&str>,
 #[cfg(test)]
 mod tests {
     use flow_control::Statement;
-    use parser::peg::{parse, JobKind};
+    use parser::peg::{parse, JobKind, RedirectFrom, Redirection};
+
+    #[test]
+    fn stderr_redirection() {
+        if let Statement::Pipelines(mut pipelines) = parse("git rev-parse --abbrev-ref HEAD ^> /dev/null") {
+            let pipeline = pipelines.remove(0);
+            assert_eq!("git", pipeline.jobs[0].args[0]);
+            assert_eq!("rev-parse", pipeline.jobs[0].args[1]);
+            assert_eq!("--abbrev-ref", pipeline.jobs[0].args[2]);
+            assert_eq!("HEAD", pipeline.jobs[0].args[3]);
+
+            let expected = Redirection {
+                from: RedirectFrom::Stderr,
+                file: "/dev/null".to_owned(),
+                append: false
+            };
+
+            assert_eq!(Some(expected), pipeline.stdout);
+        }
+    }
 
     #[test]
     fn subshells_within_subshells() {
diff --git a/src/pipe.rs b/src/pipe.rs
index 1a47ce3aaef87a26d0ca8c62ddde8c5994558027..b3ce9dce9533ea4f1f7145f505dcf1579bd68dd2 100644
--- a/src/pipe.rs
+++ b/src/pipe.rs
@@ -5,7 +5,7 @@ use std::fs::{File, OpenOptions};
 use std::thread;
 
 use status::*;
-use parser::peg::{Pipeline, JobKind};
+use parser::peg::{Pipeline, JobKind, RedirectFrom};
 
 pub fn execute_pipeline(pipeline: Pipeline) -> i32 {
     // Generate a list of commands from the given pipeline
@@ -31,7 +31,21 @@ pub fn execute_pipeline(pipeline: Pipeline) -> i32 {
                 File::create(&stdout.file)
             };
             match file {
-                Ok(f) => unsafe { command.0.stdout(Stdio::from_raw_fd(f.into_raw_fd())); },
+                Ok(f) => unsafe {
+                    match stdout.from {
+                        RedirectFrom::Both => {
+                            let fd = f.into_raw_fd();
+                            command.0.stderr(Stdio::from_raw_fd(fd));
+                            command.0.stdout(Stdio::from_raw_fd(fd));
+                        },
+                        RedirectFrom::Stderr => {
+                            command.0.stderr(Stdio::from_raw_fd(f.into_raw_fd()));
+                        },
+                        RedirectFrom::Stdout => {
+                            command.0.stdout(Stdio::from_raw_fd(f.into_raw_fd()));
+                        },
+                    }
+                },
                 Err(err) => {
                     let stderr = io::stderr();
                     let mut stderr = stderr.lock();
diff --git a/src/shell/mod.rs b/src/shell/mod.rs
index 5667a97cad512ba4c2a18f7ae9a8dcb6fd8a060a..3a845ce489c1339f4cb864709d3f55de91675584 100644
--- a/src/shell/mod.rs
+++ b/src/shell/mod.rs
@@ -188,7 +188,7 @@ impl Shell {
                 self.on_command(command);
 
                 // Mark the command in the context history if it was a success.
-                if self.previous_status == SUCCESS || self.flow_control.level > 0 {
+                if self.previous_status != NO_SUCH_COMMAND || self.flow_control.level > 0 {
                     self.set_context_history_from_vars();
                     if let Err(err) = self.context.history.push(command.into()) {
                         let stderr = io::stderr();