Java 使用bash,如何从目录中的所有文件中生成类路径?

Java 使用bash,如何从目录中的所有文件中生成类路径?,java,bash,file,directory,classpath,Java,Bash,File,Directory,Classpath,对于bash大师来说,这将是一个非常简单的免费赠品: 问题 使用bash,如何从目录中的所有文件中生成类路径 详细信息 给定目录: LIB=/path/to/project/dir/lib 它只包含*.jar文件,例如: junit-4.8.1.jar jurt-3.2.1.jar log4j-1.2.16.jar mockito-all-1.8.5.jar 我需要创建一个冒号分隔的类路径变量,格式如下: CLASSPATH=/path/to/project/dir/lib/junit-4

对于bash大师来说,这将是一个非常简单的免费赠品:

问题

使用bash,如何从目录中的所有文件中生成类路径


详细信息

给定目录:

LIB=/path/to/project/dir/lib
它只包含*.jar文件,例如:

junit-4.8.1.jar
jurt-3.2.1.jar
log4j-1.2.16.jar
mockito-all-1.8.5.jar
我需要创建一个冒号分隔的类路径变量,格式如下:

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
一些seudo代码几乎表达了我正在寻找的逻辑,大致如下:

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

通过bash脚本实现这一点的简单方法是什么?

新答案 (2012年10月)

不需要手动构建类路径列表。Java支持对包含jar文件的目录使用方便的通配符语法

java -cp "$LIB/*"
(请注意,
*
位于引号内。)

man java的解释:

为方便起见,包含basename*的类路径元素被认为等同于指定目录中所有文件的列表,扩展名为
.jar
.jar
(java程序无法区分这两个调用之间的差异)

例如,如果目录foo包含
a.jar
b.jar
,则类路径元素
foo/*
将扩展为a
a.jar:b.jar
,但jar文件的顺序未指定。列表中包括指定目录中的所有jar文件,甚至是隐藏的文件。仅由
*
组成的类路径项扩展为当前目录中所有jar文件的列表。
CLASSPATH
环境变量(在定义的地方)将类似地展开。任何类路径通配符扩展都发生在Java虚拟机启动之前-任何Java程序都不会看到未扩展的通配符,除非通过查询环境


旧答案

好 简单但不完美的解决方案:

CLASSPATH=$(echo "$LIB"/*.jar | tr ' ' ':')
有一个轻微的缺陷,这将无法正确处理带有空格的文件名。如果这很重要,请尝试这个稍微复杂一点的版本:

更好 这仅在find命令支持
-printf
(与GNU
find
一样)时才有效

如果在Mac OS X上没有GNU
find
,则可以使用
xargs

CLASSPATH=$(find "." -name '*.jar' | xargs echo | tr ' ' ':')
最好的? 另一种(更奇怪的)方法是更改字段分隔符变量
$IFS
。这看起来很奇怪,但在所有文件名中都表现良好,并且只使用shell内置

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

  • JARS
    设置为文件名数组
  • IFS
    更改为
  • 该数组将被回显,
    $IFS
    用作数组项之间的分隔符。这意味着文件名之间用冒号打印
  • 所有这些都是在一个子shell中完成的,因此对
    $IFS
    的更改不是永久性的(这将是baaad);做 CLASSPATH=$CLASSPATH:$i 完成 CLASSPATH=`echo$CLASSPATH | cut-c2-` Best 有了awk,一切都变得更好了


    这是另一种变化:

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

    printf-v
    有点像
    sprintf
    。大括号扩展将从末尾删除额外的冒号。

    需要是
    printf-v类路径“$LIB/%s”*.jar
    。对尾随冒号的调用很好,我必须查找它,看看它是否有区别,显然它有区别,它是一个有效的NUL目录,导致搜索当前目录(这可能是可取的,也可能是不可取的)。@SeigeX:我做了你建议的更改。我最初的回答是基于“目录中的所有文件”和问题中的“只包含*.jar文件”,但有选择性是值得的。谢谢你的回答。当我剪切/粘贴并运行它时,我得到一个由空格而不是冒号分隔的类路径。我不知道为什么。除此之外,它工作得很好。@gmale:我无法复制它。检查
    IFS
    是否有默认值以外的值(空格选项卡换行符),但这不应影响此值。如果执行
    printf“%s:\n”*.jar
    操作,是否看到任何空格?那printf'[%s]\n'$LIB'呢?谢谢您花时间回答。我剪切/粘贴了它,它生成了错误
    awk:cannotopenfile*.jar
    。因此,我删除了*.jar(因为所有文件都是lib目录中的jar),脚本挂起,就像等待输入一样。我尝试了其他一些调整,但我对awk的了解还不够,无法修复它。谢谢您的回复。这个简单的版本非常好用。对我来说,更好的解决方案失败了,因为printf不是find命令的有效选项(可能我需要在这台机器上使用3.2.48更新bash?)。最好的选择非常有效。当然,“good”和“best”选项都不能避开文件名中的空格,这对我来说很好,因为没有空格。@gmale-如果在使用CLASSPATH时也引用它,那么更好和最好的选项将容纳空格,如在
    java-cp“$CLASSPATH”
    中,“best”确实是最好的。“更好”的方法不会用空格处理jar文件名。我认为最常用的解决方案是
    CLASSPATH=$(查找“$LIB”-name'*.jar'| paste-sd:-)
    。那么您就不需要这种“奇怪的”数组bashism或GNU
    find
    。(我在这里使用一个显式的
    -
    输入参数,使它也适用于BSD
    粘贴
    )如果您不想设置
    类路径
    ,如果
    $LIB
    目录不包含JAR,您可以先运行
    shopt-s nullglob
    。感谢您的回复。我剪切/粘贴了这个,它运行得非常好。这是一个很好的例子,使用for循环来完成类似的事情。
    -c2-
    参数to cut做什么?我想可能是
    -c2-
    挤压在一起,但结果不同。如果我完全忽略了切割,我会得到相同的结果。这是干什么用的?这是一个很好的答案
    CLASSPATH=$(awk '$0=lib"/"FILENAME' ORS=":" lib=$LIB *.jar)
    
    printf -v CLASSPATH "$LIB/%s:" *.jar; CLASSPATH=${CLASSPATH%:}