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?

  • Can you expand your question? It's not very clear what you're asking.
    – nanny
    Commented Jan 21, 2015 at 20:18
  • Are you interested in using comint-send-string and then comint-send-input once the prior string has been sent?
    – lawlist
    Commented Jan 21, 2015 at 20:20
  • 1
    eshell does not use comint, that complicates it a bit.
    – wasamasa
    Commented Jan 21, 2015 at 20:34

4 Answers 4


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*"
  (insert "ls")
  • 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
    Commented Jan 22, 2015 at 7:31
  • 1
    I 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
    Commented Jan 22, 2015 at 9:06
  • I am having (error "No buffer named *eshell*") and can I call this through a keybinding for the latest opened buffer?
    – alper
    Commented Nov 9, 2020 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
    Commented May 27, 2023 at 6: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
  (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)
    (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
        (insert-before-markers-and-inherit ?\n))
      (if proc-running-p
          (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)
        (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
                (setq input (or input-string-a
                                   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
                                  (1- eshell-last-input-end)))
                    (run-hooks 'eshell-input-filter-functions)
                    (and (catch 'eshell-terminal
                             (if (eshell-invoke-directly cmd)
                               (eval cmd)
                               (eshell-eval-command cmd input))))
                    (eshell-reset t)
                    (run-hooks 'eshell-post-command-hook)
                    (signal 'quit nil))
                    (eshell-reset t)
                      (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
                        (setq command
                                (cons beg end) args t input-string-b)))))
        (message "Expecting completion of delimiter %c ..."
          (if (listp delim)
              (car delim)

(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* (
        (if input-string-c
          (eshell-parse-arguments--temp-buffer input-string-c)
            (if (consp command)
              (eshell-parse-arguments (car command) (cdr command))
              (let ((here (point))
                    (inhibit-point-motion-hooks t))
                  ;; FIXME: Why not use a temporary buffer and avoid this
                  ;; "insert&delete" business?  --Stef
                  (insert command)
                      (eshell-parse-arguments here (point))
                    (delete-region here (point))))))
            (lambda (cmd)
              (setq cmd (if (or (not (car eshell--sep-terms))
                                (string= (car eshell--sep-terms) ";"))
                          (eshell-parse-pipeline cmd)
                              (list ,(eshell-parse-pipeline cmd)))))
              (setq eshell--sep-terms (cdr eshell--sep-terms))
              (if eshell-in-pipeline-p
                `(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."
    (insert input-string-d)
    (let ((inhibit-point-motion-hooks t)
          (args (list t))
        (remove-text-properties (point-min) (point-max)
                                '(arg-begin nil arg-end nil))
        (goto-char (point-min))
        (if (setq
             (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)
                                        (list delim (point) (cdr args)))))
        (cdr args)))))
  • 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
    Commented Nov 9, 2020 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*"
    (insert cmd)

It will first kill the input already present, run cmd and then yank the input that was present back.


Package-install RET eshell-toggle, then use this piece of code as a function or whatever.

  (insert *command*)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.