Command Substitution in find -exec

Viewed 436

I'm trying to extract the text of a bunch of pdf's with pdftotext using find:

find /path/to/pdfs -iname "*.pdf" -exec pdftotext {} ~/Desktop/texts/{} \;

However this doesn't work because {} contains full paths (and the paths can be different). So I tried using basename, however that doesn't seem to get executed by find.

find /path/to/pdfs -iname "*.pdf" -exec pdftotext {} ~/Desktop/texts/$(basename {}) \;

I also tried backticks and various ways of quoting the entire thing. Nothing seems to work.

2 Answers

Your approach doesn't work because the $(basename {}) is executed before the find is called (shell expansions in arguments are evaluated prior to calling the command). Use the find like this:

find /path/to/pdfs -iname "*.pdf" -exec bash -c \
'dest=$(basename "$1"); pdftotext "$1" ~/Desktop/texts/"${dest%.*}.txt"' _ {}  \;

Note that some destination files may be overwritten if there are pdf files with the same base names in the directories searched.

Use -execdir instead of -exec (if your find implementation supports it). This will make find change to the directory containing the file, and then invoke the specific command using the relative filename in that directory.

Of course, this approach will lose the full pathame from any instance of {} in the command line. That includes the destination of the file generated by pdftotext. However, from your description, that seems to be what you want anyway.

Related