diff --git a/src/shell/job.rs b/src/shell/job.rs
index 1114933d13910b9234024bdf642b0f5d448b7fc7..32ed824ffcc1bab114ca38895f973dc23368ca55 100644
--- a/src/shell/job.rs
+++ b/src/shell/job.rs
@@ -4,6 +4,7 @@ use std::process::{Command, Stdio};
 // use glob::glob;
 
 use super::Shell;
+use parser::ArgumentSplitter;
 use parser::expand_string;
 use parser::pipelines::RedirectFrom;
 use smallstring::SmallString;
@@ -41,41 +42,66 @@ impl Job {
     pub(crate) fn expand(&mut self, shell: &Shell) {
         let mut expanded = Array::new();
         expanded.grow(self.args.len());
-        expanded.extend(self.args.drain().flat_map(|arg| if arg == "!!" {
-            expand_last_command(shell, false)
-        } else if arg == "!$" {
-            expand_last_command(shell, true)
-        } else {
-            expand_arg(&arg, shell)
+        expanded.extend(self.args.drain().flat_map(|arg| match arg.as_str() {
+            "!!" => expand_last_command(shell, Operation::All),
+            "!$" => expand_last_command(shell, Operation::LastArg),
+            "!0" => expand_last_command(shell, Operation::Command),
+            "!^" => expand_last_command(shell, Operation::FirstArg),
+            "!*" => expand_last_command(shell, Operation::NoCommand),
+            _ => expand_arg(&arg, shell),
         }));
         self.args = expanded;
     }
 }
 
+pub(crate) enum Operation {
+    LastArg,
+    FirstArg,
+    Command,
+    NoCommand,
+    All,
+}
+
 /// Expands the last command that was provided to the shell.
 ///
-/// If `args_only` is set to `true`, then only the arguments of
+/// If `last_arg` is set to `true`, then only the last argument of
 /// the last command will be expanded.
-fn expand_last_command(shell: &Shell, args_only: bool) -> Array {
-    // Strips the command from the supplied buffer.
-    fn get_args(buffer: &[u8]) -> &[u8] {
-        if let Some(pos) = buffer.iter().position(|&x| x == b' ') {
-            let buffer = &buffer[pos + 1..];
+pub(crate) fn expand_last_command(shell: &Shell, operation: Operation) -> Array {
+    fn get_last_arg(buffer: &str) -> &str { ArgumentSplitter::new(buffer).last().unwrap_or(buffer) }
+
+    fn get_first_arg(buffer: &str) -> &str {
+        ArgumentSplitter::new(buffer).skip(1).next().unwrap_or(buffer)
+    }
+
+    fn get_command(buffer: &str) -> &str { ArgumentSplitter::new(buffer).next().unwrap_or(buffer) }
+
+    fn get_args(buffer: &str) -> &str {
+        let bbuffer = buffer.as_bytes();
+        if let Some(pos) = bbuffer.iter().position(|&x| x == b' ') {
+            let buffer = &bbuffer[pos + 1..];
             if let Some(pos) = buffer.iter().position(|&x| x != b' ') {
-                return &buffer[pos..];
+                return unsafe { str::from_utf8_unchecked(&buffer[pos..]) };
             }
         }
 
-        &buffer
+        buffer
+    }
+
+    fn expand_args(buffer: &str, shell: &Shell) -> Array {
+        ArgumentSplitter::new(buffer).flat_map(|b| expand_arg(b, shell)).collect::<Array>()
     }
 
     if let Some(ref context) = shell.context {
         if let Some(buffer) = context.history.buffers.iter().last() {
             let buffer = buffer.as_bytes();
-            let last_arg = unsafe {
-                str::from_utf8_unchecked(if args_only { get_args(&buffer) } else { &buffer })
+            let buffer = unsafe { str::from_utf8_unchecked(&buffer) };
+            return match operation {
+                Operation::LastArg => expand_arg(get_last_arg(buffer), shell),
+                Operation::FirstArg => expand_arg(get_first_arg(buffer), shell),
+                Operation::Command => expand_arg(get_command(buffer), shell),
+                Operation::NoCommand => expand_args(get_args(buffer), shell),
+                Operation::All => expand_args(buffer, shell),
             };
-            return expand_arg(&last_arg, shell);
         }
     }