シェルコマンドやスクリプトのJavaコール
1. はじめに
LinuxでJavaプログラムを実行するとき、シェルコマンドやスクリプトを呼び出す必要があることがあります。そして、Runtime.getRuntime().exec()メソッドはこの機能を提供してくれます。Runtime.getRuntime()では、以下の種類のexec()メソッドが提供されています。
Process exec(String command)
Executes the specified string command in a separate process.
Process exec(String[] cmdarray)
Executes the specified command and variables in a separate process.
Process exec(String[] cmdarray, String[] envp)
Executes the specified commands and variables in a separate process of the specified environment.
Process exec(String[] cmdarray, String[] envp, File dir)
Executes the specified commands and variables in a separate process of the specified environment and working directory.
Process exec(String command, String[] envp)
Executes the specified string command in a separate process of the specified environment.
Process exec(String command, String[] envp, File dir)
Executes the specified string command in a separate process with the specified environment and working directory.
実際,cmdarrayはcommandと似ていますが,パラメータにenvpパラメータがないかnullに設定されている場合,呼び出したコマンドは現在のプログラムが実行されている環境で実行されることを意味し,dirパラメータがないかnullに設定されている場合,呼び出しコマンドは現在のプログラムを実行しているディレクトリで実行されることを意味するので,他のディレクトリのファイルやスクリプトは絶対パスで呼んだ方がよいでしょう.各パラメータの意味は次のとおりです.
- cmdarray。呼び出されたコマンドとその引数を含む配列。
- コマンドを使用します。指定されたシステムコマンド。
- envp: 環境変数の各要素を name=value の形式で設定した文字列の配列。子プロセスが現在のプロセスの環境を継承すべき場合、このパラメータは null になる。
- dir: 子プロセスが現在のプロセスの作業ディレクトリを継承すべき場合、このパラメータはNULLになります。
注意深い読者は、呼び出し操作を実行するために、JVMがプロセスを開始することに気づきます。したがって、プロセスクラスの次のメソッドを呼び出すことによって、呼び出し操作が正しく実行されたかどうかを知ることができます。
abstract int waitFor()
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
プロセスの終了値。慣習上、0は正常終了を、それ以外は異常終了を表す。
また、特定のシェルコマンドやスクリプトを呼び出すと戻り値があるので、その戻り値や出力をキャプチャしたらどうでしょうか?この問題を解決するために、Processクラスは提供しています。
abstract InputStream getInputStream()
Gets the input stream of the child process. It is better to buffer the input stream.
2. シェルコマンドを起動する
ここでは、説明のためにtarコマンドだけを使います。tarは、圧縮せずにパッケージングするコマンドです。また、tarの呼び出しがきちんと実行されているかどうかを確認するために、waitFor()メソッドを呼び出すことにします。
private void callCMD(String tarName, String fileName, String... workspace){
try {
String cmd = "tar -cf" + tarName + " " + fileName;
// String[] cmd = {"tar", "-cf", tarName, fileName};
File dir = null;
if(workspace[0] ! = null){
dir = new File(workspace[0]);
System.out.println(workspace[0]);
}
process = Runtime.getRuntime().exec(cmd, null, dir);
// process = Runtime.getRuntime().exec(cmd);
int status = process.waitFor();
if(status ! = 0){
System.err.println("Failed to call shell's command and the return status's is: " + status);
}
}
catch (Exception e){
e.printStackTrace();
}
}
注:コマンドをString[]に入れる場合、コマンドの各部分はString[]の中に要素として存在するか、コマンドをスペース文字で分割して得られるString[]に存在しなければなりません。
String[] cmd = {"tar", "-cf", tarName, fileName}; //right
String[] cmd = {"tar -cf", tarName, fileName}; //error
dirパラメータが何をするか説明するために、特にJavaプログラムをパッケージ化されるディレクトリであるhive/とは別のディレクトリに置いてみました。
/root/workspace/eclipse/Test/src/edu/wzm/CallShell.java
/root/experiment/hive
dirを設定しないか、dirをnullに設定すると、fileNameは相対パスでなければならず、できれば絶対パスでなければなりません。
call.callCMD("/root/experiment/hive.tar", "/root/experiment/hive", null);
// OR
call.callCMD("/root/experiment/hive.tar", "/root/experiment/hive");
もし、dirがhiveのある親ディレクトリを指すように設定していたら、もっと簡単だったでしょう。
call.callCMD("hive.tar", "hive", "/root/experiment/");
3. シェルスクリプトの呼び出し
Javaは、Shellスクリプトを呼び出すのと全く同じ方法で、Shellコマンドを呼び出します。ここでは、いくつかの追加的な側面について説明します。
- スクリプトにパラメータを渡す。
- 呼び出しの出力をキャプチャする。
- envpの使用について。
スクリプトに引数を渡すのは簡単で、呼び出したコマンドに引数を追加してString(またはString[])を形成するだけです。
呼び出しの出力のキャプチャは、前述したように Process.getInputStream() で行います。しかし、入力ストリームをバッファリングすることが推奨されます。
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
また、envpはString[]で、String[]の各要素は: name=valueの形式です。例えば、私のLinuxシステムには以下の環境変数はありませんが、私のJavaコードではenvpとして記述しています。
val=2
call=Bash Shell
呼び出したいシェルスクリプトは。/root/experiment/test.shです。
#! /usr/bin/env bash
args=1
if [ $# -eq 1 ];then
args=$1
echo "The argument is: $args"
fi
echo "This is a $call"
start=`date +%s`
sleep 3s
end=`date +%s`
cost=$((($end - $start) * $args * $val))
echo "Cost Time: $cost"
Javaの呼び出しコードは
private void callScript(String script, String args, String... workspace){
try {
String cmd = "sh " + script + " " + args;
// String[] cmd = {"sh", script, "4"};
File dir = null;
if(workspace[0] ! = null){
dir = new File(workspace[0]);
System.out.println(workspace[0]);
}
String[] evnp = {"val=2", "call=Bash Shell"};
process = Runtime.getRuntime().exec(cmd, evnp, dir);
// process = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = input.readLine()) ! = null) {
System.out.println(line);
}
input.close();
}
catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
CallShell call = new CallShell();
call.callScript("test.sh", "4", "/root/experiment/");
}
出力します。
/root/experiment/
The argument is: 4
This is a Bash Shell
Cost Time: 24
関連
-
NullPointerException - java.lang.
-
SLF4J: クラス・パスに複数のSLF4Jバインディングが含まれています。
-
java.sql.SQLException: 結果セットの開始前
-
Javaがテキストファイルを読み込む
-
JDK8 の Optional.of と Optional.ofNullable メソッドの違いと使い方を説明する。
-
Java基礎編 - オブジェクト指向
-
コンストラクタDate()が未定義である問題
-
代入の左辺は変数でなければならない 解答
-
Javaがエラーで実行される、選択が起動できない、最近起動したものがない
-
Prologでは、コンテンツは許可されていません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Eclipseは、ポップアップA Java Exception has occurred.を実行し、エラーException in threadの解決策を報告します。
-
Eclipse問題 アクセス制限。タイプ 'SunJCE' が API でないことを解決し、/jdk ディレクトリにある /jre と jre の違いについて理解を深める。
-
プロジェクトの依存関係を解決できない。
-
Solve モジュールのビルドに失敗しました。Error: ENOENT: no such file or directory エラー
-
Jsoup-Crawlingの動作
-
無効なメソッド宣言
-
-bash: java: コマンドが見つからない 解決方法
-
List list = new ArrayList(); Error: ArrayList は型に解決できません。
-
maven レポート エラー 解決不可能な親POM
-
Java JDKのダイナミックプロキシ(AOP)の使用と実装の原理分析