I'm attempting to get a list of files with find and then use pdfgrep to get a string from the file, then rename the file with that string.

The commands broken down are:

find . -name "*PayrollSelfBill_42652301*" -exec pdfgrep {}  -o -e "42652301-.{10}"

the find gets the files i'm interested in, the pdfgrep in the -exec portion pulls out the right string.

I want to mv the file held in {} to the output from pdfgrep.

I've tried creating variables (with $()/ backticks) and multiple -execs but can't seem to get anything to work.

Does anyone have and elegant solution?


1 Answer 1


For a single file, $filename, you would, if I understand you correctly, want to do something like

mv -i "$filename" "$( pdfgrep "$filename" -o -e "42652301-.{10}" )"

... assuming $filename was a name of a file in the current directory. Right? If not, the code below would not be correct either...

Ok, let's plug that into find with an -execdir:

find . -type f -name "*PayrollSelfBill_42652301*" -execdir sh -c '
    mv -i "$filename" "$( pdfgrep "$filename" -o -e "42652301-.{10}" )"' sh {} ';'

This would find the files that you are interested in and run the script fragment in the same directory as where the file was found (this is how -execdir differs from -exec).

It's possible that

find . -type f -name "*PayrollSelfBill_42652301*" \
    -execdir mv -i {} "$( pdfgrep {} -o -e "42652301-.{10}" )" ';'

would work too, actually, without the added child shell... now that I think about it. But I would feel safer calling a child shell since -execdir is a nonstandard option in find.

Assuming $pathname is one of the found files, but it's not in the current directory, then the following would do the same for that file:

mv -i "$pathname" "${pathname%/*}/$( pdfgrep "$pathname" -o -e "42652301-.{10}" )"

Here, ${pathname%/*} would expand to the directory of the found file (it's the same as $( dirname "$pathname" )).

This might work

find . -type f -name "*PayrollSelfBill_42652301*" \
    -exec  mv -i {} "$( dirname {} )/$( pdfgrep {} -o -e "42652301-.{10}" )" ';'

But we can be a bit more efficient and use -exec ... {} + to process a bunch of files in batch:

find . -type f -name "*PayrollSelfBill_42652301*" -exec sh -c '
    for pathname do
        mv -i "$pathname" "${pathname%/*}/$( pdfgrep "$pathname" -o -e "42652301-.{10}" )"
    done' sh {} +

The difference from the -execdir solution above is that only one (or very few) sh -c scripts would be started, and dirname is replaced by a quicker substitution, making it potentially quicker than the variation just previous to it.

Relate to both variations in this answer:

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.