从一个目录生成Classpath字符串是一个非常常见的问题,在使用命令提交一个Java、Spark作业时会经常遇到。通常遇到的遇到情况是:将本地目录下的Jar文件拼接成一个Classpath字符串,这时,通常我们可以使用这样的命令:
spark-submit -- class your.MainClass \
--jars $(echo /path/*.jar | tr ' ' ',') \
your-application.jar
这里的echo /path/*.jar | tr ' ' ','
是一个非常灵巧,非常简洁的拼接Classpath字符串的方法,从中也可以看到Shell的强大和灵活。本文地址:https://laurence.blog.csdn.net/article/details/131644295,转载请注明出处!
相对比较麻烦的是从S3目录生成Classpath字符串,麻烦之处在于S3的ls命令输出的文件列表格式比较复杂,需要处理多次才得得到期望的字符串。
使用aws s3 ls s3://...
列出文件列表时,有一个非常细节的问题,如果不注意会导致拼接的字符串出错:
- 如果路径是一个S3桶(路径中没有路径分割符),例如:
s3://glc-hudi-cdc-job-extra-jars
这样的路径,使用s3的ls命令列出文件时,行为和Linux的ll命令一致,没有问题:
- 如果路径是一个多级目录(不是直接在一个S3桶下),例如:
s3://apache-hudi-delta-streamer/jars
这样的路径,使用s3的ls命令列出文件时,会在第一行多生成一个header行,像是当前目录对象的一条记录:
为了兼容这两种情况,我们需要先使用grep精准匹配出的包含jar文件的行,然后再使用awk命令输出符合期望的完整路径和逗号分隔符,最后将多行归并为一行,去除末尾的逗号分隔符即可得到最后的Classpath字符串了,以下是一示例:
aws s3 ls s3://apache-hudi-delta-streamer/jars/ | grep -o '\S*\.jar$'| awk '{print "s3://apache-hudi-delta-streamer/jars/"$1","}' | tr -d '\n' | sed 's/,$//'
通常,脚本中的路径都是一个些变量,使用变量形式改写后如下:
APP_S3_HOME="s3://apache-hudi-delta-streamer"
JARS=$(aws s3 ls $APP_S3_HOME/jars/ | grep -o '\S*\.jar$'| awk '{print "'"$APP_S3_HOME/jars/"'"$1","}' | tr -d '\n' | sed 's/,$//')
然后,我们就可以在命令行中传入Classpath参数的地方写$JARS
就可以了!