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:

You must log in to answer this question.

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