Re: Extending find(1) to support -printf
Pretty late to the game, but ... On Mon, 08.09.2008 at 15:47:20 +0200, Oliver Fromme wrote: Jeremy Chadwick wrote: Equally as frustrating, mutt's backtick support will only honour the first line of input. If a backticked command returns multiple lines, only the first is read; the rest are ignored. Well, you can convert back and forth between spaces and newlines with tr(1): echo * | tr ' ' '\n' | grep -v whatever | tr '\n' ' ' If your data is not very large, you can also fool xargs(1) into doing the conversion for you $ echo * | xargs -n1 and $ ls -1 | xargs It's not pretty, but it should work. Note that ls(1) prints one file name per line, so you can simplify the above line like this: ls | grep -v whatever | tr '\n' ' ' By the way, I often use zsh in such cases. It supports extended globbing, for example, the wildcard expression *~*.(gz|bz2) matches all files _except_ the ones that end with .gz or .bz2. Indeed much more useful than fighting with find(1) and passing the file lists around. Cheers, Ulrich Spoerlein -- It is better to remain silent and be thought a fool, than to speak, and remove all doubt. ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to [EMAIL PROTECTED]
Re: Extending find(1) to support -printf
Jeremy Chadwick wrote: On Fri, Sep 05, 2008 at 03:12:53AM -0700, Jeremy Chadwick wrote: Also, some folks on #bsdports asked why I was bothering with this in the first place: mutt supports backticks to run shell commands inside of a muttrc file. See Building a list of mailboxes on the fly below: http://wiki.mutt.org/?ConfigTricks Note the find ... -printf '%h ' method. I can accomplish (just about) the same using `echo $HOME/Maildir/*`, but if I want to exclude an entry, I can't use | grep -v, because mutt doesn't support pipes within backticks. :-) Follow-up: mutt's backtick support does in fact respect pipes. My echo|grep -v was doing exactly what I requested: the grep -v was removing all output of the echo, since echo returned the results in a space-delimited format, not one per line. Hence, mailboxes was being executed without any arguments. Equally as frustrating, mutt's backtick support will only honour the first line of input. If a backticked command returns multiple lines, only the first is read; the rest are ignored. Well, you can convert back and forth between spaces and newlines with tr(1): echo * | tr ' ' '\n' | grep -v whatever | tr '\n' ' ' It's not pretty, but it should work. Note that ls(1) prints one file name per line, so you can simplify the above line like this: ls | grep -v whatever | tr '\n' ' ' By the way, I often use zsh in such cases. It supports extended globbing, for example, the wildcard expression *~*.(gz|bz2) matches all files _except_ the ones that end with .gz or .bz2. Best regards Oliver -- Oliver Fromme, secnetix GmbH Co. KG, Marktplatz 29, 85567 Grafing b. M. Handelsregister: Registergericht Muenchen, HRA 74606, Geschäftsfuehrung: secnetix Verwaltungsgesellsch. mbH, Handelsregister: Registergericht Mün- chen, HRB 125758, Geschäftsführer: Maik Bachmann, Olaf Erb, Ralf Gebhart FreeBSD-Dienstleistungen, -Produkte und mehr: http://www.secnetix.de/bsd Perl is worse than Python because people wanted it worse. -- Larry Wall ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to [EMAIL PROTECTED]
Extending find(1) to support -printf
I've been working on $SUBJECT for the past few hours, and have managed to implement a very crude subset of GNU find's features: http://www.gnu.org/software/findutils/manual/html_node/find_html/Format-Directives.html#Format-Directives I've implemented %f and %p (which appear identical to GNU find), and some escaped characters. Things I need help with, as string parsing in C has never been my forte (which will become quite obvious): 1) Getting %h to behave like GNU find. The GNU find code is significantly different than ours. As it stands, %h is broken. 2) find . -printf '\' results in odd output (SHELL=/usr/local/bin/bash on my box). Not sure why this is happening, but it's a big concern. 3) Security issues. I believe use of a large number of formatting variables could exceed the calloc()'d buffer (of MAXPATHLEN), causing a segfault at bare minimum. I'm not sure how to work around this. Also, some folks on #bsdports asked why I was bothering with this in the first place: mutt supports backticks to run shell commands inside of a muttrc file. See Building a list of mailboxes on the fly below: http://wiki.mutt.org/?ConfigTricks Note the find ... -printf '%h ' method. I can accomplish (just about) the same using `echo $HOME/Maildir/*`, but if I want to exclude an entry, I can't use | grep -v, because mutt doesn't support pipes within backticks. :-) -- | Jeremy Chadwickjdc at parodius.com | | Parodius Networking http://www.parodius.com/ | | UNIX Systems Administrator Mountain View, CA, USA | | Making life hard for others since 1977. PGP: 4BD6C0CB | diff -ruN find.orig/extern.h find/extern.h --- find.orig/extern.h 2006-05-14 13:23:00.0 -0700 +++ find/extern.h 2008-09-04 20:55:17.0 -0700 @@ -73,6 +73,7 @@ creat_fc_nouser; creat_fc_perm; creat_fc_print; +creat_fc_printf; creat_fc_regex; creat_fc_simple; creat_fc_size; @@ -107,6 +108,7 @@ exec_f f_perm; exec_f f_print; exec_f f_print0; +exec_f f_printf; exec_f f_prune; exec_f f_regex; exec_f f_size; diff -ruN find.orig/function.c find/function.c --- find.orig/function.c2006-05-27 11:27:41.0 -0700 +++ find/function.c 2008-09-05 03:01:36.0 -0700 @@ -1272,6 +1272,86 @@ /* c_print0 is the same as c_print */ /* + * -printf functions -- + * + * Always true, manipulates output based on printf()-like + * formatting characters. + */ +int +f_printf(PLAN *plan, FTSENT *entry) +{ + char *scan; + char *outptr; + char *outidx; + + if ((outptr = calloc(MAXPATHLEN, 1)) == NULL) + err(1, NULL); + + outidx = outptr; + + for (scan = plan-c_data; *scan; scan++) { + if (*scan == '%') { + if (scan[1] == 0) { + errx(1, missing format character); + } + else if (scan[1] == '%') { + *outidx++ = '%'; + } + else if (scan[1] == 'f') { + strcpy(outidx, entry-fts_name); + outidx += entry-fts_namelen; + } + /* XXX - needs to behave like GNU find %h */ + /* + else if (scan[1] == 'h') { + strcpy(outidx, entry-fts_path); + outidx += entry-fts_pathlen; + } + */ + else if (scan[1] == 'p') { + strcpy(outidx, entry-fts_path); + outidx += entry-fts_pathlen; + } + scan++; + } + else if (*scan == '\\') { + if (scan[1] == '\\') { + *outidx++ = '\\'; + } + else if (scan[1] == 'n') { + *outidx++ = '\n'; + } + else if (scan[1] == 't') { + *outidx++ = '\t'; + } + scan++; + } + else { + *outidx++ = *scan; + } + } + + (void)printf(outptr); + free(outptr); + return 1; +} + +PLAN * +c_printf(OPTION *option, char ***argvp) +{ + char *argstring; + PLAN *new; + + argstring = nextarg(option, argvp); + ftsoptions = ~FTS_NOSTAT; + isoutput = 1; + + new = palloc(option); + new-c_data = argstring; + return new; +} + +/* * -prune functions -- * * Prune a portion of the hierarchy. diff -ruN find.orig/option.c find/option.c --- find.orig/option.c 2006-04-05 16:06:11.0 -0700
Re: Extending find(1) to support -printf
On Fri, Sep 05, 2008 at 03:12:53AM -0700, Jeremy Chadwick wrote: Also, some folks on #bsdports asked why I was bothering with this in the first place: mutt supports backticks to run shell commands inside of a muttrc file. See Building a list of mailboxes on the fly below: http://wiki.mutt.org/?ConfigTricks Note the find ... -printf '%h ' method. I can accomplish (just about) the same using `echo $HOME/Maildir/*`, but if I want to exclude an entry, I can't use | grep -v, because mutt doesn't support pipes within backticks. :-) Follow-up: mutt's backtick support does in fact respect pipes. My echo|grep -v was doing exactly what I requested: the grep -v was removing all output of the echo, since echo returned the results in a space-delimited format, not one per line. Hence, mailboxes was being executed without any arguments. Equally as frustrating, mutt's backtick support will only honour the first line of input. If a backticked command returns multiple lines, only the first is read; the rest are ignored. This makes using BSD find annoying, since find always outputs results terminated with a newline. One of my peers uses find | perl -ne 'chomp; print =, $_, ' to deal with this limit, which is quite disgusting. I realise there are workarounds for the dilemma (e.g. write a shell script that provides the exact output needed), but it seems like one could kill two birds with one stone by extending BSD find to support -printf, which does not output a newline unless \n is used within the output formatting. (This also explains why the Mutt Wiki entry uses -printf '%h ', note the space.) -- | Jeremy Chadwickjdc at parodius.com | | Parodius Networking http://www.parodius.com/ | | UNIX Systems Administrator Mountain View, CA, USA | | Making life hard for others since 1977. PGP: 4BD6C0CB | ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to [EMAIL PROTECTED]
Re: Extending find(1) to support -printf
On Friday 05 September 2008 16:39, Jeremy Chadwick wrote: Equally as frustrating, mutt's backtick support will only honour the first line of input. If a backticked command returns multiple lines, only the first is read; the rest are ignored. This makes using BSD find annoying, since find always outputs results terminated with a newline. One of my peers uses find | perl -ne 'chomp; print =, $_, ' to deal with this limit, which is quite disgusting. It is, especially when you consider find ... | xargs (or find ... -print0 | xargs -0 if your filenames might cause problems (embedded spaces etc)). Jonathan ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to [EMAIL PROTECTED]