The context

I commonly execute the following variants of the grep command

  • grep --color -RHIn '' (search in the current working directory)
  • grep --color -RHIn --include='*.org' '' ~/repos/dotfiles/emacs (search in all the Org files present in a directory that contains configurations of other Emacs users)
  • grep --color -RHIn --include='init.el' ~/repos/dotfiles/emacs (search in all init.el files located in the directory mentioned above)
  • grep --color -RHIn --include='*.org' --include='*.el' '' ~/repos/dotfiles/emacs (search in all .el and .org files files located in the directory mentioned above)

Whenever I want to use one of thoose variants, I press M-x grep and manually type them.

I'm looking for ways which can help me avoid manually typing those variants whenever I want to execute any of those

Additional context

I've tried the following

(let ((grep-command "grep --color -RHIn ''")) (call-interactively grep))
(let ((grep-command "grep --color -RHIn --include='*.org' '' ~/repos/dotfiles/emacs")) (call-interactively grep))

The problem with this is that call-interactively considers the global value of the variable grep-command instead of the one provided by let. If this worked, then I would only need to do

; Variant 1

(global-set-key (kbd "C-x g 1")
                (let ((grep-command "grep --color -RHIn ''")) (call-interactively grep)))

; Variant 2

(global-set-key (kbd "C-x g 2")
                (let ((grep-command "grep --color -RHIn --include='*.org' ''")) (call-interactively grep)))

(... more variants)

The question

Do you know a better way to automate this so that I don't have to manually type any of the grep variants? Is there a package that would display something like a menu that would show a menu item with a description for each variant such that when an item is selected, grep is executed with the corresponding variant of the selected item?

If you don't have any idea, I would really appreciate if you could explain how I can make a command ((call-interactively 'grep), in this scenario) to consider the value of a variable provided by let.


2 Answers 2


The O.P. may be interested in the hydra library by Abo-Abo:


Here is a custom example that does not rely upon hydra to select from pre-defined choices. The letter c at the beginning of the interactive statement is an interactive code: https://www.gnu.org/software/emacs/manual/html_node/elisp/Interactive-Codes.html There may be a better way to get a preferred default command line as the first choice in the minibuffer that does not involve let-binding grep-host-defaults-alist to nil, but this seems to work:

;;; Needed so that `pick-a-grep' works correctly the first time it is tried;
;;; otherwise, the let-bound `grep-command' gets ignored the first time around.
(require 'grep)

(defun pick-a-grep (choice)
  "Choices for selecting from pre-defined `grep-command'."
  (interactive "c[3] is one too many. | [D]o you like eggs?")
    ((eq choice ?3)
      (let ((grep-host-defaults-alist nil)
            (grep-command "grep --color -RHIn ''"))
        (call-interactively 'grep)))
    ((eq choice ?D)
      (let ((grep-host-defaults-alist nil)
            (grep-command "grep --color -RHIn --include='*.org' '' ~/repos/dotfiles/emacs"))
        (call-interactively 'grep)))
      (message "You did not select any of the expected choices."))))
  • 1
    +1 for the hydra recommendation.
    – NickD
    Oct 1, 2020 at 2:43

As suggested in the answer of @lawlist, you can accomplish this with the hydra package.

(require 'grep)

(global-set-key (kbd "C-. g")
                (defhydra hydra-grep-variants (:color blue)
_r_: Search recursively
_co_: Search configurations (*.org)
_ce_: Search configurations (*.el)
_cm_: Search configurations (*.org, *.el)
                   ("r" (let ((grep-host-defaults-alist nil)
                              (grep-command "grep --color -RHIn '' ."))
                          (call-interactively 'grep)))
                   ("co" (let ((grep-host-defaults-alist nil)
                               (grep-command "grep --color -RHIn --include='*.org' '' ~/SourceCode/dotfiles/emacs"))
                           (call-interactively 'grep)))
                   ("ce" (let ((grep-host-defaults-alist nil)
                               (grep-find-command (concat "find " path/configs " -type f -name '*.el' ! -path '*/elpa/*' -exec grep --color -HIn '' {} +")))
                           (call-interactively 'find-grep)))
                   ("cm" (let ((grep-host-defaults-alist nil)
                               (grep-find-command (concat "find " path/configs " -type f \\( -name '*.org' -o -name '*.el' \\) ! -path '*/elpa/*' -exec grep --color -HIn '' {} +")))
                           (call-interactively 'find-grep)))))

Just press C-. C-g {key} to choose a grep variant.

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.