Hacker News new | past | comments | ask | show | jobs | submit login
Find-cmd.el: an elegant way to build up complex find(1) expressions (emacswiki.org)
9 points by wtbob on May 16, 2016 | hide | past | favorite | 2 comments

Posting because I think it's a nice example of how clean s-expression-based syntax can be:

    (find-cmd '(prune (name ".svn" ".git" ".CVS"))
              '(and (or (name "*.pl" "*.pm" "*.t")
                        (mtime "+1"))
                    (fstype "nfs" "ufs"))))
instead of:

    "find '/home/phil/' \\( \\( -name '.svn' -or -name '.git' -or
     -name '.CVS' \\) -prune -or -true \\) \\( \\( \\( -name '*.pl'
     -or -name '*.pm' -or -name '*.t' \\) -or -mtime '+1' \\) -and \\(
     -fstype 'nfs' -or -fstype 'ufs' \\) \\)"
to steal the example on the page.

Although I also like s-expressions, I'm not sure that this example is so persuasive; a lot of the visual complexity of the (awful) second example comes from having to go through so many hoops of escaping. (After writing the argument below, it occurs to me that I may be attacking a strawman, in the sense that you weren't claiming that `find-cmd`'s is the only readable way to write code, just that it is a readable way.)

The following is a thought experiment; I know that it's illegal shell syntax. If we just replace `\\(\\)` by `()` and remove spaces, then we get:

     find_noesc '/home/phil/'
          (( -name '.svn' -or -name '.git' -or -name '.CVS') -prune
          -or -true)
          ((( -name '*.pl' -or -name '*.pm' -or -name '*.t' )
               -or -mtime '+1')
          -and ( -fstype 'nfs' -or -fstype 'ufs'))
(By the way, isn't there a missing `-and` before `-prune` there? Also, couldn't we convert the `-or -true` to an `-or` with the second clause, as the `find-cmd` example does? I'm no `find` aficionado.) If we imagine a more usual in- and pre-fix calling convention, and that this removes the need for the quotes, and then if we drop the home directory (which isn't specified in the `find-cmd` call either), then we get something like:

          ((name='.svn' || name='.git' || name='.CVS')
               && prune)
     ||   (((name='*.pl' || name='*.pm' || name='*.t')
               || mtime='+1')
          && (fstype='nfs' || fstype='ufs'))
Perl-style junctions (http://doc.perl6.org/type/Junction) could make it look even better:

          (name='.svn'|'.git'|'.CVS' && prune)
     ||   ((name='*.pl'|'*.pm'|'*.t' || mtime='+1') && fstype='nfs'|'ufs')
At this stage, I think that it's fair to call it a matter of opinion which style looks better.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact