diff --git a/src/shell/binary/mod.rs b/src/shell/binary/mod.rs
index f2b6f0e3cb06e4f635e530d0b10f40103b28c00e..55e7cae29772ff24e06a7932404ac5d0a3b2c541 100644
--- a/src/shell/binary/mod.rs
+++ b/src/shell/binary/mod.rs
@@ -1,16 +1,17 @@
 //! Contains the binary logic of Ion.
 mod prompt;
 mod readln;
+mod terminate;
 
 use self::prompt::{prompt, prompt_fn};
 use self::readln::readln;
+use self::terminate::{terminate_quotes, terminate_script_quotes};
 use super::{FlowLogic, JobControl, Shell, ShellHistory};
 use super::flags::*;
 use super::flow_control::Statement;
 use super::library::IonLibrary;
 use super::status::*;
 use liner::{Buffer, Context};
-use parser::QuoteTerminator;
 use smallvec::SmallVec;
 use std::env;
 use std::fs::File;
@@ -49,50 +50,12 @@ impl Binary for Shell {
 
     fn readln(&mut self) -> Option<String> { readln(self) }
 
-    fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, mut lines: I) -> i32 {
-        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");
-                        return 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()
-            );
-            return FAILURE;
-        }
-
-        SUCCESS
+    fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, lines: I) -> i32 {
+        terminate_script_quotes(self, lines)
     }
 
     fn terminate_quotes(&mut self, command: String) -> Result<String, ()> {
-        let mut buffer = QuoteTerminator::new(command);
-        self.flow_control.level += 1;
-        while !buffer.check_termination() {
-            if let Some(command) = self.readln() {
-                buffer.append(command);
-            } else {
-                return Err(());
-            }
-        }
-        self.flow_control.level -= 1;
-        let terminated = buffer.consume();
-        Ok(terminated)
+        terminate_quotes(self, command)
     }
 
     fn execute_arguments<A: Iterator<Item = String>>(&mut self, mut args: A) {
diff --git a/src/shell/binary/terminate.rs b/src/shell/binary/terminate.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2da0894122d5690c0f4c604564d28794ccca19f4
--- /dev/null
+++ b/src/shell/binary/terminate.rs
@@ -0,0 +1,51 @@
+use super::super::{Binary, FlowLogic, Shell};
+use super::super::status::*;
+use parser::QuoteTerminator;
+
+pub(crate) fn terminate_script_quotes<I: Iterator<Item = String>>(
+    shell: &mut Shell,
+    mut lines: I,
+) -> i32 {
+    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 {
+                    eprintln!("ion: unterminated quote in script");
+                    return FAILURE;
+                }
+            }
+        }
+        shell.on_command(&buffer.consume());
+    }
+
+    // The flow control level being non zero means that we have a statement that has
+    // only been partially parsed.
+    if shell.flow_control.level != 0 {
+        eprintln!(
+            "ion: unexpected end of script: expected end block for `{}`",
+            shell.flow_control.current_statement.short()
+        );
+        return FAILURE;
+    }
+
+    SUCCESS
+}
+
+pub(crate) fn terminate_quotes(shell: &mut Shell, command: String) -> Result<String, ()> {
+    let mut buffer = QuoteTerminator::new(command);
+    shell.flow_control.level += 1;
+    while !buffer.check_termination() {
+        if let Some(command) = shell.readln() {
+            buffer.append(command);
+        } else {
+            return Err(());
+        }
+    }
+    shell.flow_control.level -= 1;
+    let terminated = buffer.consume();
+    Ok(terminated)
+}