web-dev-qa-db-fra.com

Avec bash, comment créer un chemin de classe à partir de tous les fichiers d’un répertoire?

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?

60
gMale

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 et b.JAR, l'élément de chemin d'accès aux classes foo/* est développé en un A.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'environnement CLASSPATH, 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

Bien

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:

Meilleur

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 ' ' ':')

Meilleur?

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:

  1. JARS est défini sur un tableau de noms de fichiers.
  2. IFS est remplacé par :.
  3. Le tableau est répercuté et $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).

110
John Kugelman
for i in $LIB/*.jar; do
    CLASSPATH=$CLASSPATH:$i
done
CLASSPATH=`echo $CLASSPATH | cut -c2-`
8
biziclop

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.

2
Dennis Williamson

Meilleur

Tout est meilleur avec awk =)

CLASSPATH=$(awk '$0=lib"/"FILENAME' ORS=":" lib=$LIB *.jar)
0
SiegeX