diff --git a/Cargo.lock b/Cargo.lock
index 551cd8634754a1e32ef00350f25293537e172581..7c0b7813164fd038d1b733223654d222a47ea833 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -176,6 +176,7 @@ dependencies = [
  "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "users 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -209,7 +210,7 @@ dependencies = [
 [[package]]
 name = "liner"
 version = "0.4.5"
-source = "git+https://gitlab.redox-os.org/redox-os/liner#98f723d1501701a659ab998226d7f5b32098ffc2"
+source = "git+https://gitlab.redox-os.org/redox-os/liner#82c1715faffe2535f0e9a5bc379c5c0230a360fe"
 dependencies = [
  "bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -354,6 +355,11 @@ dependencies = [
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "termion"
 version = "1.5.1"
@@ -506,6 +512,7 @@ source = "git+https://github.com/whitequark/rust-xdg#090afef2509d746e48d6bfa9b2e
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
 "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
+"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
 "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
 "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
diff --git a/Cargo.toml b/Cargo.toml
index 82cbe48f66ba72a7a7f7cf14822ea6a78749c81c..53679b83c4d154f1e1e21d37679a60ab8b4a1449 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,6 +42,7 @@ smallstring = "0.1"
 smallvec = "0.6"
 unicode-segmentation = "1.2"
 xdg = { git = "https://github.com/whitequark/rust-xdg" }
+take_mut = "0.2.2"
 
 [lib]
 path = "src/lib/lib.rs"
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index 6cea2825c4b1e0d10bdaa45b935213e1a90e9d65..db4de8723f26b09e4790f3dbd3e4ce67c458f4bb 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -17,6 +17,7 @@ extern crate glob;
 extern crate itoa;
 #[macro_use]
 extern crate lazy_static;
+extern crate take_mut;
 #[cfg(test)]
 extern crate test;
 #[cfg(all(unix, not(target_os = "redox")))]
diff --git a/src/lib/shell/flow.rs b/src/lib/shell/flow.rs
index 8847dd57ff8d5dd6aff125db293529d94c10134f..022ca5524c7e8e10ac5a2d093a1844691e5fc548 100644
--- a/src/lib/shell/flow.rs
+++ b/src/lib/shell/flow.rs
@@ -608,17 +608,7 @@ impl FlowLogic for Shell {
     }
 
     fn execute_statements(&mut self, mut statements: Vec<Statement>) -> Condition {
-        self.with_vars(|old: &Variables| {
-            let new = old.new_scope();
-            // TODO: THIS IS SUPER UNSAFE!!!!!11111
-            // I'm bypassing the borrow checker here because I'm too gosh darn lazy
-            // to make Shell take a lifetime pararmeter.
-            // THIS. IS. WRONG.
-            // This should be fixed. Some day. Ugh.
-            // Don't do this at home, kids!
-            let new: Variables<'static> = unsafe { mem::transmute(new) };
-            new
-        }, |shell| {
+        self.with_vars(|old: &Variables| old.new_scope(), |shell| {
             let mut iterator = statements.drain(..);
             while let Some(statement) = iterator.next() {
                 match shell.execute_statement(&mut iterator, statement) {
diff --git a/src/lib/shell/flow_control.rs b/src/lib/shell/flow_control.rs
index 948cdc08a8af497e0d86b7cf911323ae186291f1..9649417f6975b3dc4f97f6e72c9dd974a76ba6a3 100644
--- a/src/lib/shell/flow_control.rs
+++ b/src/lib/shell/flow_control.rs
@@ -1,8 +1,7 @@
-use super::{flow::FlowLogic, Shell, Variables};
+use super::{flow::FlowLogic, Shell};
 use parser::{assignments::*, pipelines::Pipeline};
 use smallvec::SmallVec;
 use std::fmt::{self, Display, Formatter};
-use std::mem;
 use types::Identifier;
 
 #[derive(Debug, PartialEq, Clone)]
@@ -195,15 +194,7 @@ impl Function {
             while !vars.functions.borrow().contains_key(&name) {
                 vars = vars.parent.expect("execute called on function that's not in scope");
             }
-            let vars = vars.new_scope();
-            // TODO: THIS IS SUPER UNSAFE!!!!!11111
-            // I'm bypassing the borrow checker here because I'm too gosh darn lazy
-            // to make Shell take a lifetime pararmeter.
-            // THIS. IS. WRONG.
-            // This should be fixed. Some day. Ugh.
-            // Don't do this at home, kids!
-            let vars: Variables<'static> = unsafe { mem::transmute(vars) };
-            vars
+            vars.new_scope()
         }, move |shell| {
             for (type_, value) in values {
                 match value {
diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs
index 35100d28718c7e63f8118a956d297e1e6a3f42b9..ffdf5bf0691a8d5d258b6d2f11114703e796778f 100644
--- a/src/lib/shell/mod.rs
+++ b/src/lib/shell/mod.rs
@@ -36,10 +36,11 @@ use liner::Context;
 use parser::{pipelines::Pipeline, ArgumentSplitter, Expander, Select, Terminator};
 use smallvec::SmallVec;
 use std::{
-    fs::File, io::{self, Read, Write}, iter::FromIterator, mem, ops::Deref, path::Path, ptr, process,
+    fs::File, io::{self, Read, Write}, iter::FromIterator, mem, ops::Deref, path::Path, process,
     sync::{atomic::Ordering, Arc, Mutex}, time::SystemTime,
 };
 use sys;
+use take_mut;
 use types::*;
 use xdg::BaseDirectories;
 
@@ -171,17 +172,25 @@ impl<'a> Shell {
     /// A method for temporarily using a separate set of variables for this shell.
     /// Calls the inner callback and then swaps back.
     pub fn with_vars<VF, F, T>(&mut self, variables: VF, callback: F) -> T
-        where VF: FnOnce(&Variables) -> Variables<'static>,
+        where VF: for <'b> FnOnce(&'b Variables) -> Variables<'b>,
                F: FnOnce(&mut Self) -> T
     {
-        // TODO: It's undefined behavior if variables() callback panics.
-        // This could be solved with the take-mut crate.
-        let old = mem::replace(&mut self.variables, unsafe { mem::uninitialized() });
-        let new = variables(&old);
-        unsafe { ptr::write(&mut self.variables, new); }
-
+        let mut old = None;
+        take_mut::take(&mut self.variables, |old2| {
+            old = Some(old2);
+            let new = variables(old.as_ref().unwrap());
+
+            // TODO: THIS IS SUPER UNSAFE!!!!!11111
+            // I'm bypassing the borrow checker here because I'm too gosh darn lazy
+            // to make Shell take a lifetime pararmeter.
+            // THIS. IS. WRONG.
+            // This should be fixed. Some day. Ugh.
+            // Don't do this at home, kids!
+            let new: Variables<'static> = unsafe { mem::transmute(new) };
+            new
+        });
         let value = callback(self);
-        mem::replace(&mut self.variables, old);
+        mem::replace(&mut self.variables, old.unwrap());
         value
     }