使用 bash,如何从目录中的所有文件中创建类路径?

Posted

技术标签:

【中文标题】使用 bash,如何从目录中的所有文件中创建类路径?【英文标题】:Using bash, how do you make a classpath out of all files in a directory? 【发布时间】:2011-06-11 10:05:09 【问题描述】:

这将是一个真的简单的 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

一些几乎可以表达我正在寻找的逻辑的伪代码将类似于:

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

通过 bash 脚本完成此操作的简单方法是什么?

【问题讨论】:

【参考方案1】:
for i in $LIB/*.jar; do
    CLASSPATH=$CLASSPATH:$i
done
CLASSPATH=`echo $CLASSPATH | cut -c2-`

【讨论】:

感谢您的回复。我剪切/粘贴了它,它运行得很好。这是使用 for 循环完成类似操作的一个很好的例子。 要剪切的-c2- 参数有什么作用?我认为它可能是-c2 - 挤在一起,但这会产生不同的结果。如果我完全省略剪辑,我会得到相同的结果。它有什么用? 对于可能没有xargsfind 上的-printf 选项的非bash shell 环境,这是一个很好的答案。【参考方案2】:

新答案(2012 年 10 月)

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

java -cp "$LIB/*"

(请注意,*引号内。)

来自man java的解释:

为了特别方便,包含 * 基名的类路径元素被认为等同于指定目录中所有文件的列表,扩展名为 .jar.JAR(java 程序无法区分两个调用)。

例如,如果目录 foo 包含 a.jarb.JAR,则类路径元素 foo/* 扩展为 A.jar:b.JAR,只是未指定 jar 文件的顺序。指定目录中的所有 jar 文件,即使是隐藏的,都包含在列表中。仅由 * 组成的类路径条目将扩展为当前目录中所有 jar 文件的列表。定义的CLASSPATH 环境变量将被类似地扩展。任何类路径通配符扩展都发生在 Java 虚拟机启动之前——没有 Java 程序会看到未扩展的通配符,除非通过查询环境。


旧答案

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

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

有一个小缺陷,它不能正确处理带空格的文件名。如果这很重要,请尝试这个稍微复杂一点的版本:

更好

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

这只有在你的 find 命令支持 -printf 时才有效(就像 GNU find 一样)。

如果您没有 GNU find,就像在 Mac OS X 上一样,您可以改用 xargs

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

最好的?

另一种(更奇怪的)方法是更改​​字段分隔符变量$IFS。这看起来很奇怪,但可以很好地处理所有文件名,并且只使用 shell 内置函数。

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

解释:

    JARS 设置为文件名数组。 IFS 更改为 :。 回显数组,$IFS 用作数组条目之间的分隔符。这意味着文件名之间用冒号打印。

所有这些都是在一个子 shell 中完成的,因此对 $IFS 的更改不是永久性的(这将是 baaaad)。

【讨论】:

感谢您的回复。简单版本完美运行。 better 解决方案对我来说失败了,因为 printf 不是我的 find 命令的有效选项(也许我需要更新 bash?在这台机器上使用 3.2.48)。 best 选项效果很好。当然,'good' 和 'best' 选项都不会转义文件名中的空格,这对我来说很好,因为没有。 @gmale - 如果您在使用 CLASSPATH 时也引用它,则更好和最好的选项将容纳空格,如java -cp "$CLASSPATH" “最佳”确实是最好的。 “更好”的不处理带有空格的 jar 文件名。 我认为最惯用的解决方案是CLASSPATH=$(find "$LIB" -name '*.jar'|paste -sd: -)。那么你就不需要这个“奇怪”的数组 bashism 或 GNU find。 (我在这里使用了显式的- 输入参数,使其也适用于BSD paste 如果你不想设置CLASSPATH如果$LIB目录不包含jar,你可以先运行shopt -s nullglob【参考方案3】:

这是另一个变体:

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

printf -v 有点像sprintf。大括号扩展从末尾删除了多余的冒号。

【讨论】:

需要printf -v CLASSPATH "$LIB/%s" *.jar。后面的冒号很好,我必须查一下它是否有区别,显然它确实有,它是一个有效的 NUL 目录,它会导致当前目录被搜索(这可能是可取的,也可能不是可取的)。跨度> @SeigeX:我做了你建议的改变。我最初的回答是基于“目录中的所有文件”和“只包含 *.jar 文件”的问题,但有选择性是值得的。 感谢您的回复。当我剪切/粘贴并运行它时,我得到一个由空格而不是冒号分隔的类路径。我不知道为什么。除此之外,它运作良好。 @gmale:我无法重现。检查IFS 是否具有默认值以外的值(空格制表符换行符),但这不应该影响这一点。如果你这样做printf "%s:\n" *.jar,你会看到任何空格吗? printf '[%s]\n' "$LIB"呢?【参考方案4】:

最好的

一切都更好awk =)

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

【讨论】:

感谢您花时间回答。我剪切/粘贴它并生成错误awk: can't open file *.jar。所以我删除了 *.jar (因为所有文件都是 lib 目录中的 jars)并且脚本就像在等待输入一样挂起。我尝试了其他几个调整,但我对 awk 的了解还不够,无法修复它。

以上是关于使用 bash,如何从目录中的所有文件中创建类路径?的主要内容,如果未能解决你的问题,请参考以下文章

bash 脚本,在目录中创建所有文件的数组

从文件路径中删除第一个目录组件

如何在 C++ 中创建类对象的向量?

访问Class中的常量而不在ObjectiveC中创建类的实例[重复]

在另一个类中创建类实例的问题

在层次结构中创建类的指针数组