I want to execute simple commands in eshell
without explicitly typing them into the prompt, using something like with-current-buffer
How can I do this?

- 4,056
- 1
- 23
- 43
-
Can you expand your question? It's not very clear what you're asking. – nanny Jan 21 '15 at 20:18
-
Are you interested in using `comint-send-string` and then `comint-send-input` once the prior string has been sent? – lawlist Jan 21 '15 at 20:20
-
1`eshell` does not use `comint`, that complicates it a bit. – wasamasa Jan 21 '15 at 20:34
4 Answers
My initial hunch was looking for an official command that does this already, so I've found eshell-command
. However that outputs to a separate buffer, so it's not an option.
Here's an example with ls
and an *eshell*
buffer:
(with-current-buffer "*eshell*"
(eshell-return-to-prompt)
(insert "ls")
(eshell-send-input))

- 21,803
- 1
- 65
- 97
-
caisah mentioned `with-current-buffer` in the question, so isn't `eshell-command` *precisely* what is wanted? (although re-reading, I see it's not actually clear which buffer is supposed to be current). – phils Jan 22 '15 at 07:31
-
1I assume the context to be an already existing `eshell` buffer where one can already enter commands to execute them. However there isn't any primitive to execute stuff in that buffer programmatically as if one wrote it, `eshell-command` behaves slightly different since its output cannot be obtained by normally using `eshell`. – wasamasa Jan 22 '15 at 09:06
-
I am having `(error "No buffer named *eshell*")` and can I call this through a keybinding for the latest opened buffer? – alper Nov 09 '20 at 22:12
-
@alper replace the string literal `"*eshell*"` with a call to `(eshell)` which will return the Eshell buffer (creating it if necessary). – mtraceur May 27 '23 at 06:09
The following proposed solution is intended to permit users to send input programmatically underneath the eshell
hood, rather than inserting the command into the eshell
buffer following command prompt. @lawlist has submitted a feature request for the Emacs development team to consider: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=25270
SAMPLE USAGE: (eshell-send-input nil nil nil "ls -la /")
(require 'eshell)
(defun eshell-send-input (&optional use-region queue-p no-newline input-string-a)
"Send the input received to Eshell for parsing and processing.
After `eshell-last-output-end', sends all text from that marker to
point as input. Before that marker, calls `eshell-get-old-input' to
retrieve old input, copies it to the end of the buffer, and sends it.
- If USE-REGION is non-nil, the current region (between point and mark)
will be used as input.
- If QUEUE-P is non-nil, input will be queued until the next prompt,
rather than sent to the currently active process. If no process, the
input is processed immediately.
- If NO-NEWLINE is non-nil, the input is sent without an implied final
newline."
(interactive "P")
;; Note that the input string does not include its terminal newline.
(let ((proc-running-p
(and (eshell-interactive-process)
(not queue-p)))
(inhibit-point-motion-hooks t)
after-change-functions)
(unless (and proc-running-p
(not (eq (process-status (eshell-interactive-process)) 'run)))
(if (or proc-running-p
(>= (point) eshell-last-output-end))
(goto-char (point-max))
;; This is for a situation when point is before `point-max'.
(let ((copy (or input-string-a (eshell-get-old-input use-region))))
(goto-char eshell-last-output-end)
(insert-and-inherit copy)))
(unless (or no-newline
(and eshell-send-direct-to-subprocesses
proc-running-p))
(insert-before-markers-and-inherit ?\n))
(if proc-running-p
(progn
(eshell-update-markers eshell-last-output-end)
(if (or eshell-send-direct-to-subprocesses
(= eshell-last-input-start eshell-last-input-end))
(unless no-newline
(process-send-string (eshell-interactive-process) "\n"))
(process-send-region (eshell-interactive-process)
eshell-last-input-start
eshell-last-input-end)))
(if (and (null input-string-a) (= eshell-last-output-end (point)))
;; This next line is for a situation when nothing is there --
;; i.e., just make a new command prompt.
(run-hooks 'eshell-post-command-hook)
(let (input)
(eshell-condition-case err
(progn
(setq input (or input-string-a
(buffer-substring-no-properties
eshell-last-output-end (1- (point)))))
(run-hook-with-args 'eshell-expand-input-functions
eshell-last-output-end (1- (point)))
(let ((cmd (eshell-parse-command-input
eshell-last-output-end (1- (point)) nil input-string-a)))
(when cmd
(eshell-update-markers eshell-last-output-end)
(setq input (buffer-substring-no-properties
eshell-last-input-start
(1- eshell-last-input-end)))
(run-hooks 'eshell-input-filter-functions)
(and (catch 'eshell-terminal
(ignore
(if (eshell-invoke-directly cmd)
(eval cmd)
(eshell-eval-command cmd input))))
(eshell-life-is-too-much)))))
(quit
(eshell-reset t)
(run-hooks 'eshell-post-command-hook)
(signal 'quit nil))
(error
(eshell-reset t)
(eshell-interactive-print
(concat (error-message-string err) "\n"))
(run-hooks 'eshell-post-command-hook)
(insert-and-inherit input)))))))))
(defun eshell-parse-command-input (beg end &optional args input-string-b)
"Parse the command input from BEG to END.
The difference is that `eshell-parse-command' expects a complete
command string (and will error if it doesn't get one), whereas this
function will inform the caller whether more input is required.
- If nil is returned, more input is necessary (probably because a
multi-line input string wasn't terminated properly). Otherwise, it
will return the parsed command."
(let (delim command)
(if (setq delim (catch 'eshell-incomplete
(ignore
(setq command
(eshell-parse-command
(cons beg end) args t input-string-b)))))
(ignore
(message "Expecting completion of delimiter %c ..."
(if (listp delim)
(car delim)
delim)))
command)))
(defun eshell-parse-command (command &optional args toplevel input-string-c)
"Parse the COMMAND, adding ARGS if given.
COMMAND can either be a string, or a cons cell demarcating a buffer
region. TOPLEVEL, if non-nil, means that the outermost command (the
user's input command) is being parsed, and that pre and post command
hooks should be run before and after the command."
(let* (
eshell--sep-terms
(terms
(if input-string-c
(eshell-parse-arguments--temp-buffer input-string-c)
(append
(if (consp command)
(eshell-parse-arguments (car command) (cdr command))
(let ((here (point))
(inhibit-point-motion-hooks t))
(with-silent-modifications
;; FIXME: Why not use a temporary buffer and avoid this
;; "insert&delete" business? --Stef
(insert command)
(prog1
(eshell-parse-arguments here (point))
(delete-region here (point))))))
args)))
(commands
(mapcar
(function
(lambda (cmd)
(setq cmd (if (or (not (car eshell--sep-terms))
(string= (car eshell--sep-terms) ";"))
(eshell-parse-pipeline cmd)
`(eshell-do-subjob
(list ,(eshell-parse-pipeline cmd)))))
(setq eshell--sep-terms (cdr eshell--sep-terms))
(if eshell-in-pipeline-p
cmd
`(eshell-trap-errors ,cmd))))
(eshell-separate-commands terms "[&;]" nil 'eshell--sep-terms))) )
(let ((cmd commands))
(while cmd
(if (cdr cmd)
(setcar cmd `(eshell-commands ,(car cmd))))
(setq cmd (cdr cmd))))
(if toplevel
`(eshell-commands (progn
(run-hooks 'eshell-pre-command-hook)
(catch 'top-level (progn ,@commands))
(run-hooks 'eshell-post-command-hook)))
(macroexp-progn commands))))
(defun eshell-parse-arguments--temp-buffer (input-string-d)
"Parse all of the arguments at point from BEG to END.
Returns the list of arguments in their raw form.
Point is left at the end of the arguments."
(with-temp-buffer
(insert input-string-d)
(let ((inhibit-point-motion-hooks t)
(args (list t))
delim)
(with-silent-modifications
(remove-text-properties (point-min) (point-max)
'(arg-begin nil arg-end nil))
(goto-char (point-min))
(if (setq
delim
(catch 'eshell-incomplete
(while (not (eobp))
(let* ((here (point))
(arg (eshell-parse-argument)))
(if (= (point) here)
(error "Failed to parse argument '%s'"
(buffer-substring here (point-max))))
(and arg (nconc args (list arg)))))))
(throw 'eshell-incomplete (if (listp delim)
delim
(list delim (point) (cdr args)))))
(cdr args)))))

- 18,826
- 5
- 37
- 118
-
Is it possible to make a keybinding to call eshell-send-input? ex: `(defun foo () (interactive)(eshell-send-input nil nil nil "ls"))` and keybinding to call foo ? – alper Nov 09 '20 at 22:10
I wrote this function for it,
(defun run-this-in-eshell (cmd)
"Runs the command 'cmd' in eshell."
(with-current-buffer "*eshell*"
(eshell-kill-input)
(end-of-buffer)
(insert cmd)
(eshell-send-input)
(end-of-buffer)
(yank)
))
It will first kill the input already present, run cmd
and then yank the input that was present back.

- 930
- 4
- 15
Package-install RET eshell-toggle
, then use this piece of code as a function or whatever.
(progn
(eshell-toggle)
(eshell-return-to-prompt)
(insert *command*)
(eshell-send-input))

- 11
- 1