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.

  • Do you understand what "+" does there? – Ignacio Vazquez-Abrams May 14 '18 at 17:32
  • not really to be honest.I am not an expert at shell scripting. – hebbo May 14 '18 at 17:33
  • Why do you need the -exec clause? You will list all files with find . -type f. – AFH May 14 '18 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. – hebbo May 14 '18 at 17:37
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.

  • oh...I see. You are right. I think best is to use \ instead of +. Your answer helped me search for a better solution. – hebbo May 14 '18 at 17:43
  • this is the final command: find * -type f -exec sh -c 'echo $0' {} \; – hebbo May 14 '18 at 17:44
  • @hebbo I thought you deliberately used + – Kamil Maciorowski May 14 '18 at 17:44
  • either way. Your solution is also good. – hebbo May 14 '18 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? – Kamil Maciorowski May 14 '18 at 17:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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