0

I have the following file/directory structure:

tsunami # find .
.
./dir1
./dir1/dirinner
./dir1/dirinner/innerfile
./logs
./messages

I am trying to recursively find files and process them using find/exec.

The version of find (comes with busybox) does not allow the use of the discovered file name more than once in the exec command like discussed here. So, I used one of the suggested solutions. So, I re-wrote this:

find  * -type f -exec echo {}  +

to this:

find  * -type f -exec sh -c 'echo $0' {}  +

But the new version find the innermost file only, and nothing else.

Here is the output for both:

tsunami # find  * -type f -exec echo {}  +
dir1/dirinner/innerfile logs messages
tsunami # find  * -type f -exec sh -c 'echo $0' {}  +
dir1/dirinner/innerfile

How do I fix this? I need it to find all files, not just the inner most one.

4
  • Do you understand what "+" does there? May 14, 2018 at 17:32
  • not really to be honest.I am not an expert at shell scripting. May 14, 2018 at 17:33
  • Why do you need the -exec clause? You will list all files with find . -type f.
    – AFH
    May 14, 2018 at 17:36
  • the -exec is just to show the problem. In my actual script, the -exec command does something different. I stripped it down to make it easier for people to help me out. May 14, 2018 at 17:37

1 Answer 1

2

I assume echo is just your guinea pig to run experiments on (sole find . -type f does the job of printing file paths).

In my answer I use find . … instead of find * … – for simplicity. If you have your reasons to use shell globbing then go ahead.

Your issue is because -exec … {} + syntax substitutes many paths at once in place of {}; so in -exec sh -c 'echo $0' {} + the sh gets many arguments, but $0 refers to just one, the rest remain unused.

Use "$@", it means "$1" "$2" "$3" …. Because it skips $0 you need to supply an extra (dummy) argument. For sh I use sh:

find . -type f -exec sh -c 'echo "$@"' sh {} +

Also note that if this found too many files for one command line to handle, multiple sh-s (thus multiple echo-s) would be run.


Alternatively instead of -exec … {} + use -exec … \;:

find . -type f -exec sh -c 'echo "$0"' {} \;

This will run a separate sh for every file, so $0 is enough.

Another difference is: most find implementations require {} to be just before +, but in case of \; this {} may be anywhere between -exec and \;. It means that:

  • -exec foo {} bar + is invalid;
  • -exec foo {} bar \; is OK.

This difference doesn't matter in your particular case though.

6
  • oh...I see. You are right. I think best is to use \ instead of +. Your answer helped me search for a better solution. May 14, 2018 at 17:43
  • this is the final command: find * -type f -exec sh -c 'echo $0' {} \; May 14, 2018 at 17:44
  • @hebbo I thought you deliberately used + May 14, 2018 at 17:44
  • either way. Your solution is also good. May 14, 2018 at 17:45
  • @hebbo Are you going to write your own answer? Or may I include your version in my answer to make it complete? May 14, 2018 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .