Ce sera un billet de faveur vraiment simple pour un gourou bash:
Question
Avec bash, comment créer un chemin de classe à partir de tous les fichiers d’un répertoire?
Détails
Étant donné un répertoire:
LIB=/path/to/project/dir/lib
qui ne contient que des fichiers * .jar tels que:
junit-4.8.1.jar
jurt-3.2.1.jar
log4j-1.2.16.jar
mockito-all-1.8.5.jar
J'ai besoin de créer une variable de chemin d'accès aux classes séparée par deux points sous la forme:
CLASSPATH=/path/to/project/dir/lib/junit-4.8.1.jar:/path/to/project/dir/lib/jurt-3.2.1.jar:/path/to/project/dir/lib/log4j-1.2.16.jar:/path/to/project/dir/lib/mockito-all-1.8.5.jar
Certains seudo-codes qui expriment presque la logique que je recherche ressemblent à:
for( each file in directory ) {
classpath = classpath + ":" + LIB + file.name
}
Qu'est-ce qu'un simple moyen de réaliser cela via un script bash?
Nouvelle réponse
(octobre 2012)
Il n'est pas nécessaire de construire manuellement la liste des chemins de classes. Java prend en charge une syntaxe générique pratique pour les répertoires contenant des fichiers JAR.
Java -cp "$LIB/*"
(Notez que le *
est à l'intérieur des guillemets.)
Explication de man Java
:
De manière pratique, un élément de chemin de classe contenant un nom de base * est considéré comme équivalent à la spécification d'une liste de tous les fichiers du répertoire portant l'extension
.jar
ou.JAR
(un programme Java ne peut pas distinguer les deux invocations).Par exemple, si le répertoire foo contient
a.jar
etb.JAR
, l'élément de chemin d'accès aux classesfoo/*
est développé en unA.jar:b.JAR
, sauf que l'ordre des fichiers jar n'est pas spécifié. Tous les fichiers jar du répertoire spécifié, même ceux qui sont cachés, sont inclus dans la liste. Une entrée de chemin de classe consistant simplement en*
se développe en une liste de tous les fichiers jar du répertoire en cours. La variable d'environnementCLASSPATH
, lorsqu'elle est définie, sera développée de la même manière. Toute expansion de caractère générique de chemin de classe se produit avant le démarrage de la machine virtuelle Java - aucun programme Java ne verra jamais de caractère générique non développé, sauf en interrogeant l'environnement.
Old Answer
Solution simple mais pas parfaite:
CLASSPATH=$(echo "$LIB"/*.jar | tr ' ' ':')
Il y a un léger défaut en ce que cela ne gérera pas les noms de fichiers avec des espaces correctement. Si cela compte, essayez cette version légèrement plus compliquée:
CLASSPATH=$(find "$LIB" -name '*.jar' -printf '%p:' | sed 's/:$//')
Cela ne fonctionne que si votre commande find supporte -printf
(comme le fait GNU find
).
Si vous n'avez pas GNU find
, comme sur Mac OS X, vous pouvez utiliser xargs
à la place:
CLASSPATH=$(find "." -name '*.jar' | xargs echo | tr ' ' ':')
Une autre façon (plus étrange) de le faire est de changer la variable de séparateur de champ $IFS
. Cela a l'air très étrange, mais se comportera bien avec tous les noms de fichiers et utilisera uniquement les fonctions intégrées de Shell.
CLASSPATH=$(JARS=("$LIB"/*.jar); IFS=:; echo "${JARS[*]}")
Explication:
JARS
est défini sur un tableau de noms de fichiers.IFS
est remplacé par :
.$IFS
est utilisé comme séparateur entre les entrées du tableau. Cela signifie que les noms de fichiers sont imprimés avec des deux-points.Tout cela est fait dans un sous-shell, donc le changement de $IFS
n'est pas permanent (ce qui serait baaaad).
for i in $LIB/*.jar; do
CLASSPATH=$CLASSPATH:$i
done
CLASSPATH=`echo $CLASSPATH | cut -c2-`
Voici une autre variante:
printf -v CLASSPATH "$LIB/%s:" *.jar; CLASSPATH=${CLASSPATH%:}
printf -v
est un peu comme sprintf
. L'extension d'accolade supprime les deux-points supplémentaires de la fin.
Tout est meilleur avec awk
=)
CLASSPATH=$(awk '$0=lib"/"FILENAME' ORS=":" lib=$LIB *.jar)