diff --git a/src/shell/variables.rs b/src/shell/variables.rs
index 5177a5a48cf7b3910bad62db5949cc7232538a86..edee55e8c28f92b87e12bf42d9ea93c1edd101bf 100644
--- a/src/shell/variables.rs
+++ b/src/shell/variables.rs
@@ -1,5 +1,6 @@
 use fnv::FnvHashMap;
 use std::env;
+use std::io::{self, BufRead};
 use std::process;
 
 use super::directory_stack::DirectoryStack;
@@ -14,6 +15,7 @@ use sys::getpid;
 #[cfg(all(unix, not(target_os = "unix")))]
 use sys::getpid;
 
+use sys;
 use sys::variables as self_sys;
 
 #[derive(Debug)]
@@ -80,11 +82,22 @@ impl Variables {
     pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
         where I::Item: AsRef<str>
     {
-        let mut con = Context::new();
-        for arg in args.into_iter().skip(1) {
-            match con.read_line(format!("{}=", arg.as_ref().trim()), &mut |_| {}) {
-                Ok(buffer) => self.set_var(arg.as_ref(), buffer.trim()),
-                Err(_) => return FAILURE,
+        if sys::isatty(sys::STDIN_FILENO) {
+            let mut con = Context::new();
+            for arg in args.into_iter().skip(1) {
+                match con.read_line(format!("{}=", arg.as_ref().trim()), &mut |_| {}) {
+                    Ok(buffer) => self.set_var(arg.as_ref(), buffer.trim()),
+                    Err(_) => return FAILURE,
+                }
+            }
+        } else {
+            let stdin = io::stdin();
+            let handle = stdin.lock();
+            let mut lines = handle.lines();
+            for arg in args.into_iter().skip(1) {
+                if let Some(Ok(line)) = lines.next() {
+                    self.set_var(arg.as_ref(), line.trim());
+                }
             }
         }
         SUCCESS
diff --git a/src/sys/redox.rs b/src/sys/redox.rs
index 0796a5413f43bb80a6ce0f0743deec8e66d580ec..f750d98b4ead43557df484c8783379948fd31d30 100644
--- a/src/sys/redox.rs
+++ b/src/sys/redox.rs
@@ -82,6 +82,15 @@ pub fn close(fd: RawFd) -> io::Result<()> {
     cvt(syscall::close(fd)).and(Ok(()))
 }
 
+pub fn isatty(fd: RawFd) -> bool {
+    if let Ok(fd) = syscall::dup(f, &[]) {
+        let _ = syscall::close(fd);
+        true
+    } else {
+        false
+    }
+}
+
 // Support function for converting syscall error to io error
 fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
     result.map_err(|err| io::Error::from_raw_os_error(err.errno))
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index e0a09774dbb1d5083f3a6440fa5edd0eccf78fe6..019bd395dc0df182c67ece935b9a3671464144f6 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -74,6 +74,10 @@ pub fn close(fd: RawFd) -> io::Result<()> {
     cvt(unsafe { libc::close(fd) }).and(Ok(()))
 }
 
+pub fn isatty(fd: RawFd) -> bool {
+    unsafe { libc::isatty(fd) == 1 }
+}
+
 // Support functions for converting libc return values to io errors {
 trait IsMinusOne {
     fn is_minus_one(&self) -> bool;