diff --git a/src/main.rs b/src/main.rs
index c0025929a8c639487a50f01babf7f18afa5ba92e..85ed88f4e616e27b0120230fec1150a68e671d7b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -30,7 +30,7 @@ mod shell;
 mod ascii_helpers;
 
 use builtins::Builtin;
-use shell::{Shell, signals};
+use shell::{Shell, Binary, signals};
 use std::sync::mpsc;
 use std::thread;
 
@@ -38,7 +38,7 @@ fn inner_main(sigint_rx : mpsc::Receiver<i32>) {
     let builtins = Builtin::map();
     let mut shell = Shell::new(&builtins, sigint_rx);
     shell.evaluate_init_file();
-    shell.execute();
+    shell.main();
 }
 
 #[cfg(not(target_os = "redox"))]
diff --git a/src/shell/binary.rs b/src/shell/binary.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a33fce0a9a3e9e23338aa246dce27117483f3cdc
--- /dev/null
+++ b/src/shell/binary.rs
@@ -0,0 +1,239 @@
+//! Contains the binary logic of Ion.
+
+use liner::{Buffer, Context};
+use smallvec::SmallVec;
+use std::env;
+use std::fs::File;
+use std::io::{self, Write, Read, ErrorKind};
+use std::iter::{self, FromIterator};
+use std::path::Path;
+use super::flow_control::Statement;
+use super::status::*;
+use super::{Shell, FlowLogic, JobControl, ShellHistory};
+use parser::QuoteTerminator;
+
+pub trait Binary {
+    /// Launches the shell, parses arguments, and then diverges into one of the `execution` paths.
+    fn main(self);
+    /// Parses and executes the arguments that were supplied to the shell.
+    fn execute_arguments<A: Iterator<Item = String>>(&mut self, args: A);
+    /// Creates an interactive session that reads from a prompt provided by Liner.
+    fn execute_interactive(self);
+    /// Executes all of the statements contained within a given script.
+    fn execute_script<P: AsRef<Path>>(&mut self, path: P);
+    /// Ensures that read statements from a script are terminated.
+    fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, lines: I);
+    /// Ensures that read statements from the interactive prompt is terminated.
+    fn terminate_quotes(&mut self, command: String) -> Result<String, ()>;
+}
+
+impl<'a> Binary for Shell<'a> {
+    fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, mut lines: I) {
+        while let Some(command) = lines.next() {
+            let mut buffer = QuoteTerminator::new(command);
+            while !buffer.check_termination() {
+                loop {
+                    if let Some(command) = lines.next() {
+                        buffer.append(command);
+                        break
+                    } else {
+                        let stderr = io::stderr();
+                        let _ = writeln!(stderr.lock(), "ion: unterminated quote in script");
+                        self.exit(FAILURE);
+                    }
+                }
+            }
+            self.on_command(&buffer.consume());
+        }
+        // The flow control level being non zero means that we have a statement that has
+        // only been partially parsed.
+        if self.flow_control.level != 0 {
+            eprintln!("ion: unexpected end of script: expected end block for `{}`",
+                self.flow_control.current_statement.short());
+        }
+    }
+
+    fn terminate_quotes(&mut self, command: String) -> Result<String, ()> {
+        let mut buffer = QuoteTerminator::new(command);
+        self.flow_control.level += 1;
+        while !buffer.check_termination() {
+            loop {
+                if let Some(command) = self.readln() {
+                    buffer.append(command);
+                    break
+                } else {
+                    return Err(());
+                }
+            }
+        }
+        self.flow_control.level -= 1;
+        Ok(buffer.consume())
+    }
+
+    fn execute_arguments<A: Iterator<Item = String>>(&mut self, mut args: A) {
+        if let Some(mut arg) = args.next() {
+            for argument in args {
+                arg.push(' ');
+                if argument == "" {
+                    arg.push_str("''");
+                } else {
+                    arg.push_str(&argument);
+                }
+            }
+            self.on_command(&arg);
+        } else {
+            let stderr = io::stderr();
+            let mut stderr = stderr.lock();
+            let _ = writeln!(stderr, "ion: -c requires an argument");
+            self.exit(FAILURE);
+        }
+    }
+
+    fn execute_interactive(mut self) {
+        self.context = Some({
+            let mut context = Context::new();
+            context.word_divider_fn = Box::new(word_divide);
+            if "1" == self.variables.get_var_or_empty("HISTORY_FILE_ENABLED") {
+                let path = self.variables.get_var("HISTORY_FILE").expect("shell didn't set history_file");
+                context.history.set_file_name(Some(path.clone()));
+                if !Path::new(path.as_str()).exists() {
+                    eprintln!("ion: creating history file at \"{}\"", path);
+                    if let Err(why) = File::create(path) {
+                        eprintln!("ion: could not create history file: {}", why);
+                    }
+                }
+                match context.history.load_history() {
+                    Ok(()) => {
+                        // pass
+                    }
+                    Err(ref err) if err.kind() == ErrorKind::NotFound => {
+                        let history_filename = self.variables.get_var_or_empty("HISTORY_FILE");
+                        eprintln!("ion: failed to find history file {}: {}", history_filename, err);
+                    },
+                    Err(err) => {
+                        eprintln!("ion: failed to load history: {}", err);
+                    }
+                }
+            }
+            context
+        });
+
+        self.variables.set_array (
+            "args",
+            iter::once(env::args().next().unwrap()).collect(),
+        );
+
+        loop {
+            if let Some(command) = self.readln() {
+                if ! command.is_empty() {
+                    if let Ok(command) = self.terminate_quotes(command) {
+                        // Parse and potentially execute the command.
+                        self.on_command(command.trim());
+
+                        // Mark the command in the context history if it was a success.
+                        if self.previous_status != NO_SUCH_COMMAND || self.flow_control.level > 0 {
+                            self.set_context_history_from_vars();
+                            if let Err(err) = self.context.as_mut().unwrap().history.push(command.into()) {
+                                let stderr = io::stderr();
+                                let mut stderr = stderr.lock();
+                                let _ = writeln!(stderr, "ion: {}", err);
+                            }
+                        }
+                    } else {
+                        self.flow_control.level = 0;
+                        self.flow_control.current_if_mode = 0;
+                        self.flow_control.current_statement = Statement::Default;
+                    }
+                }
+                self.update_variables();
+            } else {
+                self.flow_control.level = 0;
+                self.flow_control.current_if_mode = 0;
+                self.flow_control.current_statement = Statement::Default;
+            }
+        }
+    }
+
+    fn main(mut self) {
+        let mut args = env::args().skip(1);
+        if let Some(path) = args.next() {
+            if path == "-c" {
+                self.execute_arguments(args);
+            } else {
+                let mut array = SmallVec::from_iter(
+                    Some(path.clone().into())
+                );
+                for arg in args { array.push(arg.into()); }
+                self.variables.set_array("args", array);
+                self.execute_script(&path);
+            }
+
+            self.wait_for_background();
+            let previous_status = self.previous_status;
+            self.exit(previous_status);
+        } else {
+            self.execute_interactive();
+        }
+    }
+
+    fn execute_script<P: AsRef<Path>>(&mut self, path: P) {
+        let path = path.as_ref();
+        match File::open(path) {
+            Ok(mut file) => {
+                let capacity = file.metadata().ok().map_or(0, |x| x.len());
+                let mut command_list = String::with_capacity(capacity as usize);
+                match file.read_to_string(&mut command_list) {
+                    Ok(_) => self.terminate_script_quotes(command_list.lines().map(|x| x.to_owned())),
+                    Err(err) => {
+                        let stderr = io::stderr();
+                        let mut stderr = stderr.lock();
+                        let _ = writeln!(stderr, "ion: failed to read {:?}: {}", path, err);
+                    }
+                }
+            },
+            Err(err) => {
+                let stderr = io::stderr();
+                let mut stderr = stderr.lock();
+                let _ = writeln!(stderr, "ion: failed to open {:?}: {}", path, err);
+            }
+        }
+    }
+}
+
+fn word_divide(buf: &Buffer) -> Vec<(usize, usize)> {
+    let mut res = Vec::new();
+    let mut word_start = None;
+
+    macro_rules! check_boundary {
+        ($c:expr, $index:expr, $escaped:expr) => {{
+            if let Some(start) = word_start {
+                if $c == ' ' && !$escaped {
+                    res.push((start, $index));
+                    word_start = None;
+                }
+            } else {
+                if $c != ' ' {
+                    word_start = Some($index);
+                }
+            }
+        }}
+    }
+
+    let mut iter = buf.chars().enumerate();
+    while let Some((i, &c)) = iter.next() {
+        match c {
+            '\\' => {
+                if let Some((_, &cnext)) = iter.next() {
+                    // We use `i` in order to include the backslash as part of the word
+                    check_boundary!(cnext, i, true);
+                }
+            }
+            c => check_boundary!(c, i, false),
+        }
+    }
+    if let Some(start) = word_start {
+        // When start has been set, that means we have encountered a full word.
+        res.push((start, buf.num_chars()));
+    }
+    res
+}
diff --git a/src/shell/mod.rs b/src/shell/mod.rs
index 313904b3f21a98c9c7cc06a27dc3888252d382fd..b2d471b5c54b98aeaa28c7effac4b8e7b302dd5d 100644
--- a/src/shell/mod.rs
+++ b/src/shell/mod.rs
@@ -1,15 +1,16 @@
 mod assignments;
+mod binary;
 mod completer;
+mod flow;
+mod history;
+mod job;
+mod pipe;
 pub mod directory_stack;
 pub mod flags;
 pub mod flow_control;
 pub mod foreground;
-mod flow;
 pub mod fork;
-mod history;
 pub mod job_control;
-mod job;
-mod pipe;
 pub mod signals;
 pub mod status;
 pub mod variables;
@@ -17,81 +18,36 @@ pub mod variables;
 pub use self::history::ShellHistory;
 pub use self::job::{Job, JobKind};
 pub use self::flow::FlowLogic;
+pub use self::binary::Binary;
 
-use std::fs::File;
-use std::io::{self, ErrorKind, Read, Write};
-use std::env;
-use std::mem;
-use std::path::{PathBuf, Path};
-use std::process;
-use std::time::SystemTime;
-use std::iter::FromIterator;
-use std::sync::{Arc, Mutex};
-use std::sync::mpsc::Receiver;
-use smallvec::SmallVec;
 
 use app_dirs::{AppDataType, AppInfo, app_root};
 use builtins::*;
 use fnv::FnvHashMap;
-use liner::{Context, CursorPosition, Event, EventKind, BasicCompleter, Buffer};
-use types::*;
-use smallstring::SmallString;
+use liner::{Context, CursorPosition, Event, EventKind, BasicCompleter};
+use parser::*;
+use parser::peg::Pipeline;
 use self::completer::{MultiCompleter, IonFileCompleter};
 use self::directory_stack::DirectoryStack;
 use self::flags::*;
-use self::flow_control::{FlowControl, Function, FunctionArgument, Statement, Type};
+use self::flow_control::{FlowControl, Function, FunctionArgument, Type};
 use self::foreground::ForegroundSignals;
 use self::job_control::{JobControl, BackgroundProcess};
-use self::variables::Variables;
-use self::status::*;
 use self::pipe::PipelineExecution;
-use parser::{
-    expand_string,
-    ArgumentSplitter,
-    QuoteTerminator,
-    ExpanderFunctions,
-    Select,
-};
-
-use parser::peg::Pipeline;
-
-fn word_divide(buf: &Buffer) -> Vec<(usize, usize)> {
-    let mut res = Vec::new();
-    let mut word_start = None;
-
-    macro_rules! check_boundary {
-        ($c:expr, $index:expr, $escaped:expr) => {{
-            if let Some(start) = word_start {
-                if $c == ' ' && !$escaped {
-                    res.push((start, $index));
-                    word_start = None;
-                }
-            } else {
-                if $c != ' ' {
-                    word_start = Some($index);
-                }
-            }
-        }}
-    }
-
-    let mut iter = buf.chars().enumerate();
-    while let Some((i, &c)) = iter.next() {
-        match c {
-            '\\' => {
-                if let Some((_, &cnext)) = iter.next() {
-                    // We use `i` in order to include the backslash as part of the word
-                    check_boundary!(cnext, i, true);
-                }
-            }
-            c => check_boundary!(c, i, false),
-        }
-    }
-    if let Some(start) = word_start {
-        // When start has been set, that means we have encountered a full word.
-        res.push((start, buf.num_chars()));
-    }
-    res
-}
+use self::status::*;
+use self::variables::Variables;
+use smallstring::SmallString;
+use smallvec::SmallVec;
+use std::env;
+use std::fs::File;
+use std::io::{self, ErrorKind, Write};
+use std::mem;
+use std::path::{PathBuf, Path};
+use std::process;
+use std::sync::mpsc::Receiver;
+use std::sync::{Arc, Mutex};
+use std::time::SystemTime;
+use types::*;
 
 /// The shell structure is a megastructure that manages all of the state of the shell throughout the entirety of the
 /// program. It is initialized at the beginning of the program, and lives until the end of the program.
@@ -293,173 +249,6 @@ impl<'a> Shell<'a> {
         process::exit(status);
     }
 
-    pub fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, mut lines: I) {
-        while let Some(command) = lines.next() {
-            let mut buffer = QuoteTerminator::new(command);
-            while !buffer.check_termination() {
-                loop {
-                    if let Some(command) = lines.next() {
-                        buffer.append(command);
-                        break
-                    } else {
-                        let stderr = io::stderr();
-                        let _ = writeln!(stderr.lock(), "ion: unterminated quote in script");
-                        self.exit(FAILURE);
-                    }
-                }
-            }
-            self.on_command(&buffer.consume());
-        }
-        // The flow control level being non zero means that we have a statement that has
-        // only been partially parsed.
-        if self.flow_control.level != 0 {
-            eprintln!("ion: unexpected end of script: expected end block for `{}`",
-                      self.flow_control.current_statement.short());
-        }
-    }
-
-    pub fn terminate_quotes(&mut self, command: String) -> Result<String, ()> {
-        let mut buffer = QuoteTerminator::new(command);
-        self.flow_control.level += 1;
-        while !buffer.check_termination() {
-            loop {
-                if let Some(command) = self.readln() {
-                    buffer.append(command);
-                    break
-                } else {
-                    return Err(());
-                }
-            }
-        }
-        self.flow_control.level -= 1;
-        Ok(buffer.consume())
-    }
-
-    pub fn execute_script<P: AsRef<Path>>(&mut self, path: P) {
-        let path = path.as_ref();
-        match File::open(path) {
-            Ok(mut file) => {
-                let capacity = file.metadata().ok().map_or(0, |x| x.len());
-                let mut command_list = String::with_capacity(capacity as usize);
-                match file.read_to_string(&mut command_list) {
-                    Ok(_) => self.terminate_script_quotes(command_list.lines().map(|x| x.to_owned())),
-                    Err(err) => {
-                        let stderr = io::stderr();
-                        let mut stderr = stderr.lock();
-                        let _ = writeln!(stderr, "ion: failed to read {:?}: {}", path, err);
-                    }
-                }
-            },
-            Err(err) => {
-                let stderr = io::stderr();
-                let mut stderr = stderr.lock();
-                let _ = writeln!(stderr, "ion: failed to open {:?}: {}", path, err);
-            }
-        }
-    }
-
-    pub fn execute(&mut self) {
-        use std::iter;
-
-        let mut args = env::args().skip(1);
-
-        if let Some(path) = args.next() {
-            if path == "-c" {
-                if let Some(mut arg) = args.next() {
-                    for argument in args {
-                        arg.push(' ');
-                        if argument == "" {
-                            arg.push_str("''");
-                        } else {
-                            arg.push_str(&argument);
-                        }
-                    }
-                    self.on_command(&arg);
-                } else {
-                    let stderr = io::stderr();
-                    let mut stderr = stderr.lock();
-                    let _ = writeln!(stderr, "ion: -c requires an argument");
-                    self.exit(FAILURE);
-                }
-            } else {
-                let mut array = SmallVec::from_iter(
-                    Some(path.clone().into())
-                );
-                for arg in args { array.push(arg.into()); }
-                self.variables.set_array("args", array);
-                self.execute_script(&path);
-            }
-
-            self.wait_for_background();
-            let previous_status = self.previous_status;
-            self.exit(previous_status);
-        }
-
-        // Only interactive sessions will have a context.
-        self.context = Some({
-            let mut context = Context::new();
-            context.word_divider_fn = Box::new(word_divide);
-            if "1" == self.variables.get_var_or_empty("HISTORY_FILE_ENABLED") {
-                let path = self.variables.get_var("HISTORY_FILE").expect("shell didn't set history_file");
-                context.history.set_file_name(Some(path.clone()));
-                if !Path::new(path.as_str()).exists() {
-                    eprintln!("ion: creating history file at \"{}\"", path);
-                    if let Err(why) = File::create(path) {
-                        eprintln!("ion: could not create history file: {}", why);
-                    }
-                }
-                match context.history.load_history() {
-                    Ok(()) => {
-                        // pass
-                    }
-                    Err(ref err) if err.kind() == ErrorKind::NotFound => {
-                        let history_filename = self.variables.get_var_or_empty("HISTORY_FILE");
-                        eprintln!("ion: failed to find history file {}: {}", history_filename, err);
-                    },
-                    Err(err) => {
-                        eprintln!("ion: failed to load history: {}", err);
-                    }
-                }
-            }
-            context
-        });
-
-        self.variables.set_array (
-            "args",
-            iter::once(env::args().next().unwrap()).collect(),
-        );
-
-        loop {
-            if let Some(command) = self.readln() {
-                if ! command.is_empty() {
-                    if let Ok(command) = self.terminate_quotes(command) {
-                        // Parse and potentially execute the command.
-                        self.on_command(command.trim());
-
-                        // Mark the command in the context history if it was a success.
-                        if self.previous_status != NO_SUCH_COMMAND || self.flow_control.level > 0 {
-                            self.set_context_history_from_vars();
-                            if let Err(err) = self.context.as_mut().unwrap().history.push(command.into()) {
-                                let stderr = io::stderr();
-                                let mut stderr = stderr.lock();
-                                let _ = writeln!(stderr, "ion: {}", err);
-                            }
-                        }
-                    } else {
-                        self.flow_control.level = 0;
-                        self.flow_control.current_if_mode = 0;
-                        self.flow_control.current_statement = Statement::Default;
-                    }
-                }
-                self.update_variables();
-            } else {
-                self.flow_control.level = 0;
-                self.flow_control.current_if_mode = 0;
-                self.flow_control.current_statement = Statement::Default;
-            }
-        }
-    }
-
     /// This function updates variables that need to be kept consistent with each iteration
     /// of the prompt. For example, the PWD variable needs to be updated to reflect changes to the
     /// the current working directory.