Personally I need run many shell command in emacs, I find it is not convenient to run a shell engine (eshell) or using it separately (bash), so is there a elisp function (local provide by emacs or any other third-part library) meet my need?
The following Elisp code advises
shell-command so that you can input a
default-directory for the
shell-command if you call it with numeric prefix argument.
If the prefix argument is negative the original
shell-command code will be called without prefix argument. You get the output of the shell command in
*Shell Command Output* buffer in that case.
If the prefix argument is positive the original
shell-command gets also that prefix argument and the output is send to the current buffer.
shell-command is called non-interactively it works like expected if the first argument is a string. Otherwise the second argument should be the
default-directory to be used for the shell command and the original arguments of
shell-command should start at the third third argument of the advised version.
(defun ad-read-default-directory-args (interactive-spec) "Read default directory and apply INTERACTIVE-SPEC. Return a list (DIRECTORY PREFIX-ARG RESULT-OF-INTERACTIVE-SPEC). The default directory is only read with numeric `current-prefix-arg'." (let ((default-directory (or (and (numberp current-prefix-arg) (expand-file-name (read-directory-name "Default directory: " nil nil t))) default-directory)) (current-prefix-arg (and (numberp current-prefix-arg) (null (< current-prefix-arg 0)) current-prefix-arg))) (append (list current-prefix-arg ;; never a string default-directory) (advice-eval-interactive-spec interactive-spec)))) (defun ad-read-default-directory-&-call (fun &rest args) "Run FUN with ARGS with `default-directory' set to DIRECTORY and PREFIX-ARG. Only change `default-directory' if the prefix arg is numeric. Positive prefix args are passed to FUN negative are not." (interactive #'ad-read-default-directory-args) (if (stringp (car args)) (apply fun args) (let ((default-directory (or (cl-second args) default-directory)) (current-prefix-arg (cl-first args))) (apply fun (nthcdr 2 args))))) (advice-add 'shell-command :around #'ad-read-default-directory-&-call)
I execute all of my python code through the shell within Emacs. Here is how I do it.
Although it's not clear what specifically you're trying to call, I suspect that if you understand how this code works, you will be able to adapt it to your needs. Use the built-in Emacs help (
C-h f and
C-h v) to learn specifically what various parts of the code do.
Create a shell in which to send a command to
This function is basically a convenience wrapper around what @amitp has already posted. It first checks if a
shell process currently exists, creating one if none does. It then sends the provided
command argument to the shell and executes it, along with some repositioning of the cursor. (Essentially it pastes the
command into the shell and presses
(defun my-sh-send-command (command) "Send COMMAND to current shell process. Creates new shell process if none exists. See URL `https://stackoverflow.com/a/7053298/5065796'" (let ((proc (get-process "shell")) pbuf) (unless proc (let ((currbuff (current-buffer))) (shell) (switch-to-buffer currbuff) (setq proc (get-process "shell")) )) (setq pbuff (process-buffer proc)) (setq command-and-go (concat command "\n")) (with-current-buffer pbuff (goto-char (process-mark proc)) (insert command-and-go) (move-marker (process-mark proc) (point)) ) (process-send-string proc command-and-go)))
Send a shell command using the currently visited file
I use python, so this function concatenates the current buffer name with a
"python " prefix and sends it to the shell. Just change the
"python " part in the
(concat ...) statement to whatever you need.
(defun my-buffer-file-to-shell () "Send current buffer file to shell as python call." (interactive) (my-sh-send-command (concat "python " (buffer-file-name))))
In this case, the path is absolute and comes from
buffer-file-name. If you need to execute the code in a different directory, you will need to modify the
default-directory, as @amitp states. Note that
default-directory is buffer local. You can read more about setting
default-directory programmatically here.
Bind everything to a convenient key
I have a global shell command which runs the
main project file and is bound to
F7. If I want to run the currently visited file with python, I press
(global-set-key (kbd "<S-f7>") 'my-buffer-file-to-shell)