Invoking a complex piped find within Emacs eshell-command

139 Views Asked by At

I'm trying to do something seemingly simple: create an Emacs function to create a TAGS file for me. There are simple instructions for doing this here

(defun create-tags (dir-name)
 "Create tags file."
 (interactive "DDirectory: ")
 (eshell-command 
  (format "find %s -type f -name \"*.[ch]\" | etags -" dir-name)))

The problem is I need "cpp" files instead of "c". That means my find command has to change to this:

find %s -type f -iname "*.cpp" -or -iname "*.h"

That works great on the command line. The problem I'm having is that eshell doesn't seem to like that at all. When I execute this function, I keep getting: File not found - "*.h": Invalid argument.

The answer to this question suggests that proper use of shell-quote-argument might fix these kinds of issues, but I haven't been able to hack out a solution that works. For instance, this produces the same error:

(format "find %s -type f -iname %s -or -iname %s | etags -"
   dir-name
   (shell-quote-argument "*.cpp")
   (shell-quote-argument "*.h"))
2

There are 2 best solutions below

1
On BEST ANSWER

You're trying to use the posix syntax with the Windows find command. This is wrong for two reasons:

  • Surely you cannot hope that it supports a syntax from a different OS.
  • Windows find acts like grep, use dir instead.

Hope it'll help you.

3
On

With much help from sds and Daniele in the comments, I was finally able to figure out the issue.

There were two issues with what I was doing:

  1. I was using a bash solution with an ms-dos command shell. The DOS "find" is a totally different command than the Unix find, so it makes perfect sense that it was complaining about its parameters.
  2. The usual quoting issues. My etags exe had a space in its path. I tried fixing this with shell-quote-argument, but with the MS-DOS shell all that does is put escaped quotes around the argument. You still have to manually escape any backslashes, and the DOS shell requires those in its file paths.

For those interested, the working command under Windows is:

(defun create-tags (dir-name)
  "Create tags file."
  (interactive "DDirectory: ")
  (shell-command
   (format "cd %s & dir /b /s *.h *.cpp | %s -"
       dir-name
       (shell-quote-argument "C:\\Program Files\\Emacs\\emacs-25.0\\bin\\etags.exe"))))

The only quirk is that when Emacs prompts you for a directory, you have to make sure to give it one the DOS shell can handle. ~/dirname will not work. There's probably a fix for that, for someone with better emacs-fu than I care to devote to the issue.