0

If I want to execute a shell command on a region I know I can use shell-command-on-region via M-|, what if the command I want to redirect my selection does not accept redirection to it's standard input.

In my case I would like to redirect my an active region to python -m doctest In the shell I could use process substitution like python -m doctest -v <( echo '>>> print("hello")\nhello')

Is there a direct way to that in emacs, or do I need to write some elisp to get the active region and build the shell command myself?


update:

Not sure if this is a good solution and what will happen if the string contains quotes like ', but seems to work at the moment, I'll appreciate any suggestions.

(defun my/python/run-doctest-on-region ()
  (interactive)
  (let* ((text-to-shell-cmd (if (use-region-p)
                                (buffer-substring-no-properties (region-beginning)
                                                                (region-end))
                              (buffer-substring-no-properties (point-min)
                                                              (point-max))))
        (cmd (concat "python -m doctest -v <( echo '" text-to-shell-cmd
                      "')")))
    (shell-command cmd)))

2 Answers 2

1

You can use something like the following with M-|:

cat > tmp.txt && python -m doctest -v tmp.txt
2
  • that makes sense, but this would create a tmp.txt file every time I run the command.
    – Cesc
    Aug 27, 2018 at 15:54
  • @Cesc That's right. It's up to you how to deal with the temporary file. Usually people put temporary files under $TMPDIR. You can delete the temporary file in the end of the command if you want to.
    – xuchunyang
    Aug 27, 2018 at 19:48
0

Building up on @xuchunyang answer. Since the function I posted in the question was having problems dealing with single quotes in coda, I finally decided to modify the previous function, like so:

(defun my/python/run-doctest-on-region-or-buffer ()
  (interactive)
  (let* ((tmp-file (concat (getenv "TMPDIR")
                          "tmp.txt"))
        (start (if (use-region-p)
                    (region-beginning)
                  (point-min)))
        (end (if (use-region-p)
                  (region-end)
                (point-max)))
        (buffer "*Python Doctest Output*")
        (command (s-join " "
                          (list "cat >" tmp-file "&& python -m doctest -v"
                                tmp-file))))
    (call-shell-region start end command nil buffer)
    (pop-to-buffer buffer)))

This way I don't need to type cat > tmp.txt && python -m doctest -v tmp.txt via M-|

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.