How can this src vs. build tree timestamp comparison be faster?
-
12-09-2019 - |
Question
for n in `cd src; find . -name "*.java"; cd -`;
do a=`echo $n | cut -d '.' -f2`;
if [[ src/$a.java -nt build/$a.class ]];
then echo src/$a.java;
fi;
done
It lists all the java files in the src tree; then for each one, it removes the suffix ".java" (cut -d '.' -f2
because find .
output is prefixed with .
). It then uses -nt
to test if the java file in the src tree is newer than the corresponding class file in the build tree; if it is newer, it is output. [javac can then use this to compile only the needed src files, instead of using ant
or make
]
The problem is that it is too slow, taking about 275ms. How to make it faster?
Or is there a faster way to do this in bash? I can't see how to do it with find
, diff
, rsync
nor make
(which doesn't seem to traverse trees automatically, and needs explicitly listed source files).
Solution
try this:
for f in src/*.java; do
file=`basename $f`;
if [[ src/$file -nt build/${file//.java/} ]]; then
echo src/$file;
fi;
done
OTHER TIPS
I don't know if this structure would be any faster, but it might be worth a try:
while read n
do
# capture the basename all at once
[[ $n =~ src/(.*)\.java ]] # escape the parentheses for Bash < 3.2 (or thereabouts)
[[ $n -nt "build/${BASH_REMATCH[1]}.class" ]] && echo $n
done < <(find src -name "*.java")
The while
form probably won't provide any boost. The collapsed if
may. The regex might provide a small contribution.
As you've found out, eliminating a call to cut
has made the biggest difference.
ant performs smart building logic, it will not build a class unless the source was modified.
You might also like to look into scons which is not a native Java build tool but is very handy at compiling efficient complex build trees and does have java builder as well.
Adopting kon's approach to the filename munging, the speed improves from 320ms to 45ms on average. Thanks kon!
for n in `cd src; find . -name "*.java"; cd -`; do
if [[ src/$n -nt build/${n/.java/.class} ]];
then echo src/$n;
fi;
done
The original is a bit slower now (was 275ms; now 320ms); I don't know why. I'm using the same line. Maybe different system sources after playing a video.
EDIT re rst's comment: mangling the "src/" away instead of cd src;
... cd -;
. Note that both $n
and $n2
are used [you can't nest the ${var/A/B} construct, can you?]
for n in `find src -name "*.java"`; do
n2=${n/src/}
if [[ $n -nt build/${n2/.java/.class} ]];
then echo $n;
fi;
done