brostone51 brostone51 - 1 year ago 39
Bash Question

Collect jars into a tar without directory

I have a large project that creates a large number of jars in a path similar to

project/subproject/target/subproject.jar
. I want to make a command to collect all the jars into one compressed tar, but without the directories. The command I have come up with so far is:
find project -name \*.jar -exec tar -rvf Collectors.tar.gz -C $(dirname {}) $(basename {}) \;
but this isn't quite working as I am intending, the directories are still there.

Does anyone have any ideas for how to resolve this issue?

Answer Source

Your command is quite close, but the problem is that Bash is executing $(dirname {}) and $(basename {}) before executing find; so your command expands to this:

find project -name \*.jar -exec tar -rvf Collectors.tar.gz -C . {} \;

where the -C . is a no-op and the {} just expands to the full relative directory+filename.

One general-purpose way to fix this sort of thing is to wrap up the argument to -exec in a Bash one-liner, so you invoke Bash for each individual file, and let it execute the dirname and basename at the right time:

find project -name \*.jar -exec bash -c 'tar -rvf Collectors.tar.gz -C "$(dirname "$1")" "$(basename "$1")"' '' '{}' \;

In your specific case, however, I'd point you to find's -execdir action, which is the same as -exec except that it cd's into the file's directory first. So you can simply write:

find project -name '*.jar' -execdir tar -rvf "$PWD/Collectors.tar.gz" '{}' \;

(Note that $PWD part, which is to make sure that you write to the Collectors.tar.gz in the current directory, rather than in the directory that find -execdir will cd into.)