Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Consider the following files:

$ find findtest                     
findtest
findtest/test1
findtest/test1/start.ksh
findtest/test2
findtest/test2/start.ksh
findtest/test3
findtest/test3/start.ksh
findtest/test4
findtest/test4/start.ksh

My question is about the use of {} in the -exec call. It works as I would expect it when designating the result file:

$ find findtest -name test[1-4] -exec ls -d {} \;           
findtest/test1
findtest/test2
findtest/test3
findtest/test4

However it doesn't seem to be expanded when used in a path:

$ find findtest -name test[1-4] -exec md5sum {}/start.ksh \;     
md5sum: {}/start.ksh: No such file or directory
md5sum: {}/start.ksh: No such file or directory
md5sum: {}/start.ksh: No such file or directory
md5sum: {}/start.ksh: No such file or directory

How can I use find -type d -exec to access lower hierarchy files? I know I can use a for loop like this, but I am curious to know if it can be done in one find call:

$ for f in $(find findtest -name test[1-4]); do md5sum "$f"/start.ksh; done
d41d8cd98f00b204e9800998ecf8427e  findtest/test1/start.ksh
d41d8cd98f00b204e9800998ecf8427e  findtest/test2/start.ksh
d41d8cd98f00b204e9800998ecf8427e  findtest/test3/start.ksh
d41d8cd98f00b204e9800998ecf8427e  findtest/test4/start.ksh
share|improve this question
    
I've tested your second example (md5sum with find), and it seems to work on Linux. Thus it seems to be a Solaris flavor. –  lgarzo Jun 14 '12 at 10:54
    
That wouldn't be the first time something like that happens. Solaris is a strange beast. I used to get irritated at first, but I'm finding out these shortecomings usually have a reason. –  rahmu Jun 14 '12 at 10:57
    
It's still better to pass it via xargs, it would be much faster. –  Jiri Xichtkniha Jun 14 '12 at 11:26
    
@Jiri Not sure it would be measurable in that case. Anyway, find doesn't need xargs as -exec has the same feature built in. –  jlliagre Jun 14 '12 at 11:50
1  
@Jiri Not necessarily. Have a look at the second suggestion in my reply. –  jlliagre Jun 14 '12 at 14:16

2 Answers 2

up vote 5 down vote accepted

The POSIX standard for the find command only mandates an isolated {} to be replaced by the filename, and only the first one. Using {}/start.ksh lead to unspecified behavior.

An argument containing only the two characters "{}" shall be replaced by the set of aggregated pathnames, with each pathname passed as a separate argument to the invoked utility in the same order that it was aggregated. The size of any set of two or more pathnames shall be limited such that execution of the utility does not cause the system's {ARG_MAX} limit to be exceeded. If more than one argument containing only the two characters "{}" is present, the behavior is unspecified.

If a utility_name or argument string contains the two characters "{}", but not just the two characters "{}", it is implementation-defined whether find replaces those two characters or uses the string without change.

One way to do what you want with Solaris find would be that command:

find findtest -name "test[1-4]" -exec sh -c 'md5sum $1/start.ksh' foo {} \;

A faster way would be:

find findtest -name "test[1-4]" -exec sh -c 'for i; do md5sum "$i/start.ksh"; done' foo {} + 
share|improve this answer
    
Thanks for a spot on answer. I would be very interested to know why your second command is faster than the first? Is it ksh specific or is it the same on all shells? –  rahmu Jun 14 '12 at 12:53
1  
@rahmu It is faster because it concatenates all of the arguments and runs them in a single shell session, instead of creating a new shell session for each argument. –  Chris Down Jun 14 '12 at 13:29
    
@rahmu That's it. The + terminator is equivalent but simpler than using xargs. There is nothing ksh specific in the commands I suggested, they would run with the legacy /bin/sh, bash or ksh. –  jlliagre Jun 14 '12 at 14:14
    
Oh yes. I got confused by for i;. This is what I suspected to be shell specific. To make sure I got it right, is this just an implicit way of writing for i in $*? –  rahmu Jun 14 '12 at 15:02
    
It is almost equivalent. More precisely, it an implicit way of writing for i in "$@" –  jlliagre Jun 14 '12 at 22:57
  1. Actually your shell is expanding test[1-4] before it invokes find. You need to escape it with '…'
  2. {} gets treated as pattern only when it's being a separate token

-exec itself is usually costy and recommended to be used either with trailing +, or avoided in favor of feeding xargs.

I know I can use a for loop like this, but I am curious to know if it can be done in one find call:

find findtest -name 'test[1-4]' -print0 | xargs -0I{} -- md5sum '{}/start.ksh' — runs md5sum efficiently — with all file names given at once.

share|improve this answer
    
This won't work on Solaris. Your find and xargs commands are non standard compliant by using Gnuisms. –  jlliagre Jun 14 '12 at 14:18
    
@jlliagre, ORLY? How does it works fine for me on SunOS solaris 5.11 11.0 i86pc i386 i86pc, then? –  poige Jun 14 '12 at 14:26
    
It indeed works on Solaris 11 because you have /usr/gnu/bin first in your PATH. rahmu is very likely using Solaris 10 or older that do not bundle gnu find and xargs. Otherwise find findtest -name test[1-4] -exec md5sum {}/start.ksh \; would have work in the first place. –  jlliagre Jun 14 '12 at 14:53
1  
Granted. The find ... -print0 and xargs -0 Gnuisms have been integrated in Solaris 11 standard commands to improve user familiarity. I should rephrase my comment, "This won't work on Solaris 10 or older, which is what rahmu is using". –  jlliagre Jun 14 '12 at 23:45
1  
No problem for Solaris users who actually had a reliable solution since 1992 (first implemented by David Korn in 1988 on SVR4.0). in-ulm.de/~mascheck/various/find/dgk-20010326.html –  jlliagre Jun 15 '12 at 7:24

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.