summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/misc/eshell.texi8
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/eshell/esh-var.el50
-rw-r--r--test/lisp/eshell/esh-var-tests.el7
4 files changed, 50 insertions, 22 deletions
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index fb9a563b696..da5e1ef1d03 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -624,9 +624,11 @@ each argument as a string, separated by a space.
@item env
@cmindex env
-Prints the current environment variables. Unlike in Bash, this
-command does not yet support running commands with a modified
-environment.
+With no arguments, print the current environment variables. If you
+pass arguments to this command, then @command{env} will execute the
+arguments as a command. If you pass any initial arguments of the form
+@samp{@var{var}=@var{value}}, @command{env} will first set @var{var}
+to @var{value} before running the command.
@item eshell-debug
@cmindex eshell-debug
diff --git a/etc/NEWS b/etc/NEWS
index 0d7d7d5ab60..37264f2f1f1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -657,6 +657,13 @@ For more information, see the "(eshell) Built-ins" node in the Eshell
manual.
+++
+*** Eshell's 'env' command now supports running commands.
+Like in many other shells, Eshell's 'env' command now lets you run a
+command passed as arguments to 'env'. If you pass any initial
+arguments of the form 'VAR=VALUE', 'env' will first set 'VAR' to
+'VALUE' before running the command.
+
++++
*** New special reference type '#<marker POSITION BUFFER>'.
This special reference type returns a marker at 'POSITION' in
'BUFFER'. You can insert it by typing or using the new interactive
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index 1d90fbdd8ee..627cbb17797 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -304,27 +304,36 @@ This is set to t in `eshell-local-variable-bindings' (which see).")
(add-hook 'pcomplete-try-first-hook
#'eshell-complete-variable-assignment nil t)))
-(defun eshell-handle-local-variables ()
- "Allow for the syntax `VAR=val <command> <args>'."
+(defun eshell-parse-local-variables (args)
+ "Parse a list of ARGS, looking for variable assignments.
+Variable assignments are of the form \"VAR=value\". If ARGS
+begins with any such assignments, throw `eshell-replace-command'
+with a form that will temporarily set those variables.
+Otherwise, return nil."
;; Handle local variable settings by let-binding the entries in
;; `eshell-local-variable-bindings' and calling `eshell-set-variable'
;; for each variable before the command is invoked.
(let ((setvar "\\`\\([A-Za-z_][A-Za-z0-9_]*\\)=\\(.*\\)\\'")
- (command eshell-last-command-name)
- (args eshell-last-arguments))
- (when (and (stringp command) (string-match setvar command))
+ (head (car args))
+ (rest (cdr args)))
+ (when (and (stringp head) (string-match setvar head))
(throw 'eshell-replace-command
`(let ,eshell-local-variable-bindings
,@(let (locals)
- (while (and (stringp command)
- (string-match setvar command))
+ (while (and (stringp head)
+ (string-match setvar head))
(push `(eshell-set-variable
- ,(match-string 1 command)
- ,(match-string 2 command))
+ ,(match-string 1 head)
+ ,(match-string 2 head))
locals)
- (setq command (pop args)))
+ (setq head (pop rest)))
(nreverse locals))
- (eshell-named-command ,command ,(list 'quote args)))))))
+ (eshell-named-command ,head ',rest))))))
+
+(defun eshell-handle-local-variables ()
+ "Allow for the syntax `VAR=val <command> <args>'."
+ (eshell-parse-local-variables (cons eshell-last-command-name
+ eshell-last-arguments)))
(defun eshell-interpolate-variable ()
"Parse a variable interpolation.
@@ -414,19 +423,22 @@ the values of nil for each."
obarray #'boundp))
(pcomplete-here))))
-;; FIXME the real "env" command does more than this, it runs a program
-;; in a modified environment.
(defun eshell/env (&rest args)
"Implementation of `env' in Lisp."
- (eshell-init-print-buffer)
(eshell-eval-using-options
"env" args
- '((?h "help" nil nil "show this usage screen")
+ '(;; FIXME: Support more "env" options, like "--unset".
+ (?h "help" nil nil "show this usage screen")
:external "env"
- :usage "<no arguments>")
- (dolist (setting (sort (eshell-environment-variables) 'string-lessp))
- (eshell-buffered-print setting "\n"))
- (eshell-flush)))
+ :parse-leading-options-only
+ :usage "[NAME=VALUE]... [COMMAND [ARG]...]")
+ (if args
+ (or (eshell-parse-local-variables args)
+ (eshell-named-command (car args) (cdr args)))
+ (eshell-init-print-buffer)
+ (dolist (setting (sort (eshell-environment-variables) 'string-lessp))
+ (eshell-buffered-print setting "\n"))
+ (eshell-flush))))
(defun eshell-insert-envvar (envvar-name)
"Insert ENVVAR-NAME into the current buffer at point."
diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el
index bb3d18abf6d..b94e8a276d7 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -661,6 +661,13 @@ nil, use FUNCTION instead."
(eshell-insert-command "VAR=hello cd ..")
(should (equal default-directory parent-directory)))))
+(ert-deftest esh-var-test/local-variables/env ()
+ "Test that \"env VAR=value command\" temporarily sets variables."
+ (with-temp-eshell
+ (push "VAR=value" process-environment)
+ (eshell-match-command-output "env VAR=hello env" "VAR=hello\n")
+ (should (equal (getenv "VAR") "value"))))
+
;; Variable aliases