Usando bash, ¿cómo se hace una classpath de todos los archivos en un directorio?

Este será un regalo de promoción muy simple para un gurú de bash:

Pregunta

Usando bash, ¿cómo se hace una classpath de todos los archivos en un directorio?


Detalles

Dado un directorio:

LIB=/path/to/project/dir/lib 

que no contiene nada más que archivos * .jar como:

 junit-4.8.1.jar jurt-3.2.1.jar log4j-1.2.16.jar mockito-all-1.8.5.jar 

Necesito crear una variable classpath separada por dos puntos en el formulario:

 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 

Algún seudo código que casi expresa la lógica que estoy buscando estaría en la línea de:

 for( each file in directory ) { classpath = classpath + ":" + LIB + file.name } 

¿Cuál es una forma simple de lograr esto a través del script bash?

Nueva respuesta
(Octubre 2012)

No es necesario comstackr manualmente la lista de classpath. Java admite una syntax comodín conveniente para directorios que contienen archivos jar.

 java -cp "$LIB/*" 

(Tenga en cuenta que el * está dentro de las comillas).

Explicación del man java :

Como conveniencia especial, un elemento de ruta de clase que contiene un nombre base de * se considera equivalente a especificar una lista de todos los archivos en el directorio con la extensión .jar o .JAR (un progtwig Java no puede distinguir entre las dos invocaciones).

Por ejemplo, si el directorio foo contiene a.jar y b.JAR , entonces el elemento de ruta de clase foo/* se expande a A.jar:b.JAR , excepto que el orden de los archivos jar no está especificado. Todos los archivos jar en el directorio especificado, incluso los ocultos, se incluyen en la lista. Una entrada classpath que consiste simplemente en * expande a una lista de todos los archivos jar en el directorio actual. La variable de entorno CLASSPATH , si está definida, se expandirá de manera similar. Cualquier expansión de comodín de classpath ocurre antes de que se inicie la máquina virtual Java: ningún progtwig Java verá comodines no expandidos, excepto al consultar el entorno.


Vieja respuesta

Bueno

Solución simple pero no perfecta:

 CLASSPATH=$(echo "$LIB"/*.jar | tr ' ' ':') 

Hay una pequeña falla en que esto no manejará los nombres de los archivos con espacios correctos. Si eso importa, pruebe esta versión un poco más complicada:

Mejor

 CLASSPATH=$(find "$LIB" -name '*.jar' -printf '%p:' | sed 's/:$//') 

Esto solo funciona si su comando find admite -printf (como lo hace GNU find ).

Si no tiene GNU find , como en Mac OS X, puede usar xargs lugar:

 CLASSPATH=$(find "." -name '*.jar' | xargs echo | tr ' ' ':') 

¿Mejor?

Otra forma (más extraña) de hacerlo es cambiar la variable separadora de campo $IFS . Esto tiene un aspecto muy extraño, pero se comportará bien con todos los nombres de archivos y solo utiliza integrables de shell.

 CLASSPATH=$(JARS=("$LIB"/*.jar); IFS=:; echo "${JARS[*]}") 

Explicación:

  1. JARS se establece en una matriz de nombres de archivo.
  2. IFS se cambia a :
  3. La matriz se repite, y $IFS se usa como el separador entre las entradas de la matriz. Lo que significa que los nombres de los archivos están impresos con dos puntos entre ellos.

Todo esto se hace en un subconjunto, por lo que el cambio a $IFS no es permanente (lo cual sería baaaad).

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

Aquí hay otra variación:

 printf -v CLASSPATH "$LIB/%s:" *.jar; CLASSPATH=${CLASSPATH%:} 

printf -v es algo así como sprintf . La expansión de la abrazadera elimina el colon extra del final.

Bestest

Todo es mejor con awk =)

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