Something like the following is what I what I’m after,
but my code doesn’t work, no matter how I escape {} and + ;
find ./ -maxdepth 1 -type d -name '.*' -exec
find {} -maxdepth 1 -type f -name '*.ini' -exec
md5sum {} \; ;
After seeing this Unix-&-Linux question,
I found that the following code works, but it isn’t nesting find as such, and I suspect there is a better way to do this particular job.
find ./ -maxdepth 1 -type d -name '.*'
-exec bash -c 'for x; do
find "$x" -maxdepth 1 -type f -name "*.ini"
-exec md5sum {} ;;
done' _ {} +
Is there some way to nest find -exec without the need to invoke
a shell (as above), with all its whacky quoteing and escape constraints?
Or can this be done directly in a single find command,
using a blend of its many parameters?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
I would try using a single find like:
find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +
or even (no find at all, just shell globbing)
md5sum .*/*.ini
although this lacks the -type f check so only works if you have no directories/non-files ending in .ini. If you do you could use
for x in .*/*.ini; do
if [ -f "$x" ]; then
md5sum "$x"
fi
done
which would however lose the advantage of only needing one md5sum invocation.
Edit
For a general and safe method of chaining find, you can do something like
find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]
Method 2
Your original problem does not require calling find recursively but I suppose that was not the point.
I believe it is not possible to call find recursively in the way you want.
The following is not calling find recursively (or nesting, whatever it is called) either, but can’t you just take a result set of the first find and feed it to the second one? This is how I would instinctively do:
find `find ./ -maxdepth 1 -type d -name '.*'`
-maxdepth 1 -type f -name '*.ini' -exec md5sum {} ;
You could also use xargs for executing the second find.
Update:
I wanted to add that because most UNIX utilities take several file name arguments instead of one, you can usually avoid the -exec altogether:
md5sum `find `find ./ -maxdepth 1 -type d -name '.*'` -maxdepth 1 -type f -name '*.ini'`
When nesting backticks you just add backslashes before the inner ones.
If we imagine that md5sum takes only one filename argument, we can always wrap it in a for loop:
for f in `find `find ./ -maxdepth 1 -type d -name '.*'` -maxdepth 1 -type f -name '*.ini'`
do
md5sum $f
done
Note that this becomes more difficult if file/directory names starting with - or containing a space are involved. UNIX utilities do not play nicely with them. In that case adding ./, -- or quotes is needed.
Obviously the original example is not a good one, because we could just do:
md5sum .*/*.ini
Method 3
At least I managed to nest 2 find commands:
find ~ -maxdepth 1 -type d -name '.*' -execdir
find {} -maxdepth 1 -type f -name '*.ini' ;
But I didn’t solve to invoke another -exec(dir) – call from there.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0