使用 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 -
挤在一起,但这会产生不同的结果。如果我完全省略剪辑,我会得到相同的结果。它有什么用?
对于可能没有xargs
或find
上的-printf
选项的非bash shell 环境,这是一个很好的答案。【参考方案2】:
新答案(2012 年 10 月)
无需手动构建类路径列表。 Java 支持对包含 jar 文件的目录使用方便的通配符语法。
java -cp "$LIB/*"
(请注意,*
在内引号内。)
来自man java
的解释:
为了特别方便,包含 * 基名的类路径元素被认为等同于指定目录中所有文件的列表,扩展名为
.jar
或.JAR
(java 程序无法区分两个调用)。例如,如果目录 foo 包含
a.jar
和b.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,如何从目录中的所有文件中创建类路径?的主要内容,如果未能解决你的问题,请参考以下文章