Comment exécuter par programmation une commande en eshell?


8

Je veux exécuter des commandes simples eshellsans les taper explicitement dans l'invite, en utilisant quelque chose comme with-current-bufferComment puis-je faire cela?


Pouvez-vous développer votre question? Ce que vous demandez n'est pas très clair.
nounou

Êtes-vous intéressé à utiliser comint-send-stringpuis comint-send-inputune fois que la chaîne précédente a été envoyée?
Lawlist

1
eshelln'utilise pas comint, ça complique un peu.
wasamasa

Réponses:


11

Mon intuition initiale cherchait une commande officielle qui le fait déjà, donc j'ai trouvé eshell-command. Cependant, cela sort dans un tampon séparé, donc ce n'est pas une option.

Voici un exemple avec lset un *eshell*tampon:

(with-current-buffer "*eshell*"
  (eshell-return-to-prompt)
  (insert "ls")
  (eshell-send-input))

caisah mentionné with-current-bufferdans la question, n'est-ce pas eshell-command précisément ce que l'on veut? (bien qu'en relisant, je vois qu'il n'est pas vraiment clair quel tampon est censé être actuel).
phils

1
Je suppose que le contexte est un eshelltampon déjà existant où l'on peut déjà entrer des commandes pour les exécuter. Cependant, il n'y a pas de primitive pour exécuter des choses dans ce tampon par programmation comme si on l'avait écrit, eshell-commandse comporte légèrement différemment car sa sortie ne peut pas être obtenue en utilisant normalement eshell.
wasamasa

2

La solution proposée ci-dessous est destinée à permettre aux utilisateurs d'envoyer des entrées par programmation sous le eshellcapot, plutôt que d'insérer la commande dans l' eshellinvite de commande tampon suivante. @lawlist a soumis une demande de fonctionnalité à l'attention de l'équipe de développement Emacs: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=25270

EXEMPLE D'UTILISATION : (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)))))

0

J'ai écrit cette fonction pour ça,

(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)
    ))

Il supprimera d'abord l'entrée déjà présente, exécutera cmdpuis tirera sur l'entrée qui était présente.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.