Jarにライブラリを必要とするグルーヴィーなスクリプトがあります。それをクラスパスに追加するにはどうすればよいですか?スクリプトを実行可能にしたいので、スクリプトの先頭で#!/usr/bin/env groovy
を使用しています。
本当に必要な場合は、実行時にJARをロードすることもできます。
this.getClass().classLoader.rootLoader.addURL(new File("file.jar").toURL())
#!/usr/bin/env groovy
でgroovyスクリプトを開始することには非常に重要な制限があります-追加の引数は追加できません。クラスパスは設定できません。これは groovy の問題ではなく、Shebang(#!
)の動作の制限です。追加の引数はすべて単一の引数として扱われるため、#!/usr/bin/env groovy -d
は/usr/bin/env
にgroovy -d
rathenコマンドを実行し、groovy
引数がd
の場合。
Groovyスクリプトでbashでgroovyをブートストラップすることを含む問題の回避策があります。
#!/bin/bash
//usr/bin/env groovy -cp extra.jar:spring.jar:etc.jar -d -Dlog4j.configuration=file:/etc/myapp/log4j.xml "$0" $@; exit $?
import org.springframework.class.from.jar
//other groovy code
println 'Hello'
すべての魔法は最初の2行で発生します。最初の行は、これがbash
スクリプトであることを示しています。 bash
は実行を開始し、最初の行を確認します。 bash
では、#
はコメント用で、//
はルートディレクトリである/
に縮小されます。したがって、bash
は/usr/bin/env groovy -cp extra.jar:spring.jar:etc.jar -d -Dlog4j.configuration=file:/etc/myapp/log4j.xml "$0" $@
を実行し、必要なすべての引数でgroovyを開始します。 "$0"
はスクリプトへのパスであり、$@
は引数です。 groovyが実行され、最初の2行が無視され、groovyスクリプトが表示され、bash
に戻ります。 bash
は、groovyからのステータスコードで終了(exit $?1
)します。
Jarを$ HOME/.groovy/libに追加できます
私のお気に入りの方法は、Groovy Grapesを使用することです。これらは、Maven Central Repositoryにアクセスし、参照されたjarをダウンロードして、クラスパスに配置します。その後、他のライブラリと同様にライブラリを使用できます。構文は本当に簡単です:
@Grab(group='com.google.collections', module='google-collections', version='1.0')
詳細を読むことができます こちら 。ここでの大きな利点の1つは、スクリプトを配布するときに依存関係を配布する必要がないことです。この方法の唯一の欠点は、JarがMavenリポジトリにある必要があることです。
Groovy Grapeを試すこともできます。アノテーションを使用してクラスパスを変更できます。現在は実験的ですが、かなりクールです。 docs.groovy-lang.org/.../grape を参照してください
Javaの場合と同じです。
これは、MySQLステータス監視スクリプトの実行例です。 mysql.jarには、スクリプトstatus.groovyから呼び出すMySQLコネクターが含まれています。
groovy -cp mysql.jar status.groovy ct1
以下は、 Patrickのソリューション 、 Maarteen Boekholdのソリューション 、およびLinuxとCygwinの両方で機能するfoozbarのコメントの組み合わせです。
#!/bin/bash
// 2>/dev/null; SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
// 2>/dev/null; OPTS="-cp $SCRIPT_DIR/lib/extra.jar:$SCRIPT_DIR/lib/spring.jar"
// 2>/dev/null; OPTS="$OPTS -d"
// 2>/dev/null; OPTS="$OPTS -Dlog4j.configuration=file:/etc/myapp/log4j.xml"
// 2>/dev/null; exec groovy $OPTS "$0" "$@"; exit $?
import org.springframework.class.from.jar
//other groovy code
println 'Hello'
使い方:
//
は有効なgroovyコメントであるため、bashコマンドはすべてGroovyによって無視されます。//
はエラーを返しますが、エラー出力は/dev/null
にリダイレクトされるため、表示されません。exec
は、新しいプロセスをフォークすることなく、現在のプロセスの現在のプログラムを置き換えます。したがって、groovyは元のスクリプトプロセス内で実行されます(ps
は、プロセスをgroovy実行可能ファイルではなくスクリプトとして表示します)exit $?
に続くexec groovy
ステートメントは、bashがスクリプトの残りをbashスクリプトとして解釈しようとするのを防ぎ、groovyスクリプトからの戻りコードも保持します。上記のbashトリックは、スクリプト内で通常のimportステートメントを使用できるため、 RootLoaderトリック よりも便利な場合があります。 RootLoaderトリックを使用すると、リフレクションを使用してすべてのクラスを強制的にロードできます。これは、JDBCドライバーをロードする必要がある場合など、状況によっては問題ありませんが、他の状況では不便です。
スクリプトがCygwinで決して実行されないことがわかっている場合、PatrickまたはMaarteenのソリューションを使用すると、エラーの生成と破棄のオーバーヘッドを回避できるため、パフォーマンスがわずかに向上する可能性があります。
@Patrickに彼の答えを追加したことは、私を大いに助けてくれました。最近、別のトリックを発見しました。
多数のjarをすべて1行でクラスパスに追加すると、事態はまったく読めなくなる可能性があります。しかし、次のことができます!
#!/bin/bash
//bin/true && OPTS="-cp blah.jar -Dmyopt=value"
//bin/true && OPTS="$OPTS -Dmoreopts=value2"
//usr/bin/env groovy $OPTS "$0" $@; exit $?
println "inside my groovy script"
この方法で管理しやすい部分に分解できるコマンドラインの複雑さに想像力をかきたててください
マールテン
import
宣言の直前に使用したい場合、次のようにできます:)
// printEmployees.groovy
this.class.classLoader.rootLoader.addURL(
new URL("file:///C:/app/Dustin/product/11.1.0/db_1/jdbc/lib/ojdbc6.jar"))
import groovy.sql.Sql
sql = Sql.newInstance("jdbc:Oracle:thin:@localhost:1521:orcl", "hr", "hr",
"Oracle.jdbc.pool.OracleDataSource")
sql.eachRow("SELECT employee_id, last_name, first_name FROM employees")
{
println "The employee's name is ${it.first_name} ${it.last_name}."
}
これから引用 javaworld.com article 。