Bagaimana cara menjalankan perintah di eshell secara terprogram?
8
Saya ingin menjalankan perintah sederhana eshelltanpa mengetik secara eksplisit ke prompt, menggunakan sesuatu seperti with-current-bufferBagaimana saya bisa melakukan ini?
Bisakah Anda memperluas pertanyaan Anda? Tidak terlalu jelas apa yang Anda tanyakan.
pengasuh
Apakah Anda tertarik menggunakan comint-send-stringdan kemudian comint-send-inputsetelah string sebelumnya telah dikirim?
hukum
1
eshelltidak digunakan comint, itu menyulitkannya sedikit.
wasamasa
Jawaban:
11
Firasat awal saya sedang mencari perintah resmi yang sudah melakukan ini, jadi saya sudah menemukan eshell-command. Namun itu output ke buffer terpisah, jadi itu bukan opsi.
caisah disebutkan with-current-bufferdalam pertanyaan, jadi bukankah eshell-commandtepatnya apa yang diinginkan? (Meskipun membaca ulang, saya melihat itu sebenarnya tidak jelas buffer mana yang seharusnya saat ini).
phils
1
Saya menganggap konteksnya sebagai eshellbuffer yang sudah ada di mana orang sudah bisa memasukkan perintah untuk mengeksekusi mereka. Namun tidak ada primitif untuk mengeksekusi hal-hal dalam buffer secara terprogram seolah-olah orang menulisnya, eshell-commandberperilaku sedikit berbeda karena outputnya tidak dapat diperoleh dengan menggunakan normal eshell.
wasamasa
2
Solusi yang diusulkan berikut ini dimaksudkan untuk mengizinkan pengguna untuk mengirim input secara terprogram di bawah eshellkap, daripada memasukkan perintah ke dalam eshellbuffer prompt perintah berikut. @lawlist telah mengirimkan permintaan fitur untuk tim pengembangan Emacs untuk dipertimbangkan: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=25270
PENGGUNAAN SAMPEL : (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 'quitnil))(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)))))
(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)))
Pertama-tama akan mematikan input yang sudah ada, menjalankan cmddan kemudian menarik input yang ada kembali.
comint-send-string
dan kemudiancomint-send-input
setelah string sebelumnya telah dikirim?eshell
tidak digunakancomint
, itu menyulitkannya sedikit.Jawaban:
Firasat awal saya sedang mencari perintah resmi yang sudah melakukan ini, jadi saya sudah menemukan
eshell-command
. Namun itu output ke buffer terpisah, jadi itu bukan opsi.Berikut ini contoh
ls
dan*eshell*
buffer:sumber
with-current-buffer
dalam pertanyaan, jadi bukankaheshell-command
tepatnya apa yang diinginkan? (Meskipun membaca ulang, saya melihat itu sebenarnya tidak jelas buffer mana yang seharusnya saat ini).eshell
buffer yang sudah ada di mana orang sudah bisa memasukkan perintah untuk mengeksekusi mereka. Namun tidak ada primitif untuk mengeksekusi hal-hal dalam buffer secara terprogram seolah-olah orang menulisnya,eshell-command
berperilaku sedikit berbeda karena outputnya tidak dapat diperoleh dengan menggunakan normaleshell
.Solusi yang diusulkan berikut ini dimaksudkan untuk mengizinkan pengguna untuk mengirim input secara terprogram di bawah
eshell
kap, daripada memasukkan perintah ke dalameshell
buffer prompt perintah berikut. @lawlist telah mengirimkan permintaan fitur untuk tim pengembangan Emacs untuk dipertimbangkan: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=25270PENGGUNAAN SAMPEL :
(eshell-send-input nil nil nil "ls -la /")
sumber
Saya menulis fungsi ini untuk itu,
Pertama-tama akan mematikan input yang sudah ada, menjalankan
cmd
dan kemudian menarik input yang ada kembali.sumber