shelljava的簡單介紹

本文目錄一覽:

在Java中執行某個shell命令,會怎麼樣?

Java中執行某個shell命令會執行相應的命令。

java實現執行shell的演算法如下:

public void execCommand(String command) throws IOException {

Runtime runtime = Runtime.getRuntime();

Process proc = runtime.exec(command);

try {

if (proc.waitFor() != 0) {

System.err.println(“exit value = ” + proc.exitValue());

}

BufferedReader in = new BufferedReader(new InputStreamReader(

proc.getInputStream()));

StringBuffer stringBuffer = new StringBuffer();

String line = null;

while ((line = in.readLine()) != null) {

stringBuffer.append(line+”-“);

}

//這裡返回執行結果,並列印。

System.out.println(stringBuffer.toString());

} catch (InterruptedException e) {

System.err.println(e);

}

}

比如:echo.sh

內容如下:echo “test java call shell and return value”.

那麼:

try {

execCommand(../../shell/echo.sh);

} catch (IOException e) {

e.printStackTrace();

}

就會列印出:test java call shell and return value

java怎麼執行shell腳本

如果shell腳本和java程序運行在不同的伺服器上,可以使用遠程執行Linux命令執行包,使用ssh2協議連接遠程伺服器,並發送執行命令就行了,ganymed.ssh2相關mave配置如下,你可以自己百度搜索相關資料。

如果shell腳本和java程序在同一台伺服器上,

這裡不得不提到java的process類了。

process這個類是一個抽象類,封裝了一個進程(你在調用linux的命令或者shell腳本就是為了執行一個在linux下執行的程序,所以應該使用process類)。

process類提供了執行從進程輸入,執行輸出到進程,等待進程完成,檢查進程的推出狀態,以及shut down掉進程。

dependency  

  groupIdcom.ganymed.ssh2/groupId  

  artifactIdganymed-ssh2-build/artifactId  

  version210/version  

 /dependency

本地執行命令代碼如下:

String shpath=”/test/test.sh”;   //程序路徑

    Process process =null;

    String command1 = 「chmod 777 」 + shpath;

    process = Runtime.getRuntime().exec(command1);

    process.waitFor();

如何在java中執行shell腳本

過CommandHelper.execute方法可以執行命令,該類實現

複製代碼代碼如下:

package javaapplication3;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

/**

*

* @author chenshu

*/

public class CommandHelper {

//default time out, in millseconds

public static int DEFAULT_TIMEOUT;

public static final int DEFAULT_INTERVAL = 1000;

public static long START;

public static CommandResult exec(String command) throws IOException, InterruptedException {

Process process = Runtime.getRuntime().exec(command);

CommandResult commandResult = wait(process);

if (process != null) {

process.destroy();

}

return commandResult;

}

private static boolean isOverTime() {

return System.currentTimeMillis() – START = DEFAULT_TIMEOUT;

}

private static CommandResult wait(Process process) throws InterruptedException, IOException {

BufferedReader errorStreamReader = null;

BufferedReader inputStreamReader = null;

try {

errorStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

inputStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

//timeout control

START = System.currentTimeMillis();

boolean isFinished = false;

for (;;) {

if (isOverTime()) {

CommandResult result = new CommandResult();

result.setExitValue(CommandResult.EXIT_VALUE_TIMEOUT);

result.setOutput(“Command process timeout”);

return result;

}

if (isFinished) {

CommandResult result = new CommandResult();

result.setExitValue(process.waitFor());

//parse error info

if (errorStreamReader.ready()) {

StringBuilder buffer = new StringBuilder();

String line;

while ((line = errorStreamReader.readLine()) != null) {

buffer.append(line);

}

result.setError(buffer.toString());

}

//parse info

if (inputStreamReader.ready()) {

StringBuilder buffer = new StringBuilder();

String line;

while ((line = inputStreamReader.readLine()) != null) {

buffer.append(line);

}

result.setOutput(buffer.toString());

}

return result;

}

try {

isFinished = true;

process.exitValue();

} catch (IllegalThreadStateException e) {

// process hasn’t finished yet

isFinished = false;

Thread.sleep(DEFAULT_INTERVAL);

}

}

} finally {

if (errorStreamReader != null) {

try {

errorStreamReader.close();

} catch (IOException e) {

}

}

if (inputStreamReader != null) {

try {

inputStreamReader.close();

} catch (IOException e) {

}

}

}

}

}

CommandHelper類使用了CommandResult對象輸出結果錯誤信息。該類實現

複製代碼代碼如下:

package javaapplication3;

/**

*

* @author chenshu

*/

public class CommandResult {

public static final int EXIT_VALUE_TIMEOUT=-1;

private String output;

void setOutput(String error) {

output=error;

}

String getOutput(){

return output;

}

int exitValue;

void setExitValue(int value) {

exitValue=value;

}

int getExitValue(){

return exitValue;

}

private String error;

/**

* @return the error

*/

public String getError() {

return error;

}

/**

* @param error the error to set

*/

public void setError(String error) {

this.error = error;

}

}

怎麼通過java去調用並執行shell腳本以及問題總結

對於第一個問題:java抓取,並且把結果打包。那麼比較直接的做法就是,java接收各種消息(db,metaq等等),然後藉助於jstorm集群進行調度和抓取。

最後把抓取的結果保存到一個文件中,並且通過調用shell打包, 回傳。 也許有同學會問,

為什麼不直接把java調用odps直接保存文件,答案是,我們的集群不是hz集群,直接上傳odps速度很有問題,因此先打包比較合適。(這裡不糾結設計了,我們回到正題)

java調用shell的方法

通過ProcessBuilder進行調度

這種方法比較直觀,而且參數的設置也比較方便, 比如我在實踐中的代碼(我隱藏了部分業務代碼):

ProcessBuilderpb = new ProcessBuilder(“./” + RUNNING_SHELL_FILE, param1,

param2, param3);

pb.directory(new File(SHELL_FILE_DIR));

int runningStatus = 0;

String s = null;

try {

Process p = pb.start();

try {

runningStatus = p.waitFor();

} catch (InterruptedException e) {

}

} catch (IOException e) {

}

if (runningStatus != 0) {

}

return;

這裡有必要解釋一下幾個參數:

RUNNING_SHELL_FILE:要運行的腳本

SHELL_FILE_DIR:要運行的腳本所在的目錄; 當然你也可以把要運行的腳本寫成全路徑。

runningStatus:運行狀態,0標識正常。 詳細可以看java文檔。

param1, param2, param3:可以在RUNNING_SHELL_FILE腳本中直接通過1,2,$3分別拿到的參數。

直接通過系統Runtime執行shell

這個方法比較暴力,也比較常用, 代碼如下:

p = Runtime.getRuntime().exec(SHELL_FILE_DIR + RUNNING_SHELL_FILE + ” “+param1+” “+param2+” “+param3);

p.waitFor();

我們發現,通過Runtime的方式並沒有builder那麼方便,特別是參數方面,必須自己加空格分開,因為exec會把整個字元串作為shell運行。

可能存在的問題以及解決方法

如果你覺得通過上面就能滿足你的需求,那麼可能是要碰壁了。你會遇到以下情況。

沒許可權運行

這個情況我們團隊的朱東方就遇到了, 在做DTS遷移的過程中,要執行包裡面的shell腳本, 解壓出來了之後,發現執行不了。 那麼就按照上面的方法授權吧

java進行一直等待shell返回

這個問題估計更加經常遇到。 原因是, shell腳本中有echo或者print輸出, 導致緩衝區被用完了! 為了避免這種情況, 一定要把緩衝區讀一下, 好處就是,可以對shell的具體運行狀態進行log出來。 比如上面我的例子中我會變成:

ProcessBuilderpb = new ProcessBuilder(“./” + RUNNING_SHELL_FILE, keyword.trim(),

taskId.toString(), fileName);

pb.directory(new File(CASPERJS_FILE_DIR));

int runningStatus = 0;

String s = null;

try {

Process p = pb.start();

BufferedReaderstdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));

BufferedReaderstdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));

while ((s = stdInput.readLine()) != null) {

LOG.error(s);

}

while ((s = stdError.readLine()) != null) {

LOG.error(s);

}

try {

runningStatus = p.waitFor();

} catch (InterruptedException e) {

}

記得在start()之後, waitFor()之前把緩衝區讀出來打log, 就可以看到你的shell為什麼會沒有按照預期運行。 這個還有一個好處是,可以讀shell裡面輸出的結果, 方便java代碼進一步操作。

也許你還會遇到這個問題,明明手工可以運行的命令,java調用的shell中某一些命令居然不能執行,報錯:命令不存在!

比如我在使用casperjs的時候,手工去執行shell明明是可以執行的,但是java調用的時候,發現總是出錯。

通過讀取緩衝區就能發現錯誤日誌了。 我發現即便自己把安裝的casperjs的bin已經加入了path中(/etc/profile,

各種bashrc中)還不夠。 比如:

exportNODE_HOME=”/home/admin/node”

exportCASPERJS_HOME=”/home/admin/casperjs”

exportPHANTOMJS_HOME=”/home/admin/phantomjs”

exportPATH=$PATH:$JAVA_HOME/bin:/root/bin:$NODE_HOME/bin:$CASPERJS_HOME/bin:$PHANTOMJS_HOME/bin

原來是因為java在調用shell的時候,默認用的是系統的/bin/下的指令。特別是你用root許可權運行的時候。 這時候,你要在/bin下加軟鏈了。針對我上面的例子,就要在/bin下加軟鏈:

ln -s /home/admin/casperjs/bin/casperjscasperjs;

ln -s /home/admin/node/bin/nodenode;

ln -s /home/admin/phantomjs/bin/phantomjsphantomjs;

這樣,問題就可以解決了。

如果是通過java調用shell進行打包,那麼要注意路徑的問題了

因為shell裡面tar的壓縮和解壓可不能直接寫:

tar -zcf /home/admin/data/result.tar.gz /home/admin/data/result

直接給你報錯,因為tar的壓縮源必須到路徑下面, 因此可以寫成

tar -zcf /home/admin/data/result.tar.gz -C /home/admin/data/ result

如果我的shell是在jar包中怎麼辦?

答案是:解壓出來。再按照上面指示進行操作。(1)找到路徑

String jarPath = findClassJarPath(ClassLoaderUtil.class);

JarFiletopLevelJarFile = null;

try {

topLevelJarFile = new JarFile(jarPath);

EnumerationJarEntry entries = topLevelJarFile.entries();

while (entries.hasMoreElements()) {

JarEntryentry = entries.nextElement();

if (!entry.isDirectory() entry.getName().endsWith(“.sh”)) {

對你的shell文件進行處理

}

}

對文件處理的方法就簡單了,直接touch一個臨時文件,然後把數據流寫入,代碼:

FileUtils.touch(tempjline);

tempjline.deleteOnExit();

FileOutputStreamfos = new FileOutputStream(tempjline);

IOUtils.copy(ClassLoaderUtil.class.getResourceAsStream(r), fos);

fos.close();

用shell腳本怎樣編譯java工程

用shell腳本怎樣編譯java工程

編譯java工程一般直接用IDE或者用Ant、Maven之類的工具,很少有人用純shell來編譯java工程。正好遇到這樣一個應該,用這篇博文做一下記錄。

案例:用eclipse寫了一個java project,然後編譯打成jar包。

這個可以採用eclipse自帶的Export就可以導出jar了。但是為了軟體自動化等巴拉巴拉的原因,採用存shell腳本編譯。

如圖所示,java project的名稱為iec104,下面src是源文件目錄,bin是所引用的jar包目錄,現在要進行編譯,並且打成jar,如果對jar有所了解,都知道jar有個MANIFEST.MF文件,iec104工程的MF文件內容如下:

就是制定了運行的main-class(有public static void main(String args[])的類)。

將這個文件拷貝到iec104的根目錄下,然後執行腳本compile.sh,內容如下:

#!/bin/bash

cur_dir=$(pwd)

echo $cur_dir

function do_compile_iec104(){

#    echo $cur_dir

iec104=$cur_dir/iec104

iec104_src=$cur_dir/iec104/src

iec104_bin=$cur_dir/iec104/bin

#    echo $iec104_src

#    echo $iec104_bin

iec104_class=$cur_dir/iec104/class

# 將iec104的src目錄下的所有java文件的名稱存入到iec104/src/sources.list文件中

rm -rf $iec104_src/sources.list

find $iec104_src -name “*.java” $iec104_src/sources.list

cat  $iec104_src/sources.list

# $iec104_class是存放編譯的class文件的目錄

rm -rf $iec104_class

mkdir $iec104_class

# 這裡開始編譯java文件,注意這裡的-encoding utf-8,剛開始並沒有加入這個,然後就報了一堆錯誤,糾結了很久才發現,這裡給各位提個醒了。

javac -d $iec104_class -encoding utf-8 -classpath $iec104_bin/classes12.jar:$iec104_bin/junit-4.10.jar:$iec104_bin/log4j-1.2.17.jar:$iec104_bin/mysql-connector-java-5.0.5-bin.jar:$iec104_bin/RXTXcomm.jar -g -sourcepath $iec104_src @$iec104_src/sources.list

# 由於用到了log4j,所以要將log4j的配置文件一併放入,如果沒有用到,可以忽略這句

cp $iec104_src/log4j.properties $iec104_class

# 如果原來在iec104目錄下有jar報就刪除掉,因為要生成新的

rm $iec104/iec104.jar

# 這裡要cd到存放class的目錄,否則如果採用絕對路徑編譯,編譯出來的jar包裡面就是絕對路徑了,這樣就會有問題

# jar -cvfm $iec104/iec104.jar $iec104/MANIFEST.MF $iec104_class/*這樣是錯誤的

cd $iec104_class

jar -cvfm $iec104/iec104.jar $iec104/MANIFEST.MF *

# 賦予可執行許可權

sudo chmod a+x $iec104/iec104.jar

}

do_compile_iec104

exit 0

運行這個腳本(linux下)就可以編譯並且在iec104的目錄下就可以看到iec104.jar文件了。

這裡補充下java命令的基本知識:

javac 用於編譯Java文件,格式為:

java [options] [sourcefiles] [@files]

其中:

options:命令行選項;

sourcefiles:一個或多個要編譯的源文件;

@files:一個或多個對源文件進行列表的文件,有時候要編譯的文件很多,一個個敲命令會顯得很長,也不方便修改,可以把要編譯的源文件列在文件中,在文件名前加@,這樣就可以對多個文件進行編譯,對編譯一個工程很有用,方便,省事。

有幾個比較重要的選項:

-d 用於指定編譯成的class文件的存放位置,預設情況下不指定class文件的存放目錄,編譯的class文件將和源文件在同一目錄下;

-classpath 可以簡寫成-cp,用於搜索編譯所需的class文件,指出編譯所用到的class文件的位置,如jar、zip或者其他包含class文件的目錄,指定該選項會覆蓋CLASSPATH的設定;

-sourcepath用於搜索編譯所需的源文件(即java文件),指定要搜索的源文件的位置,如jar、zip或其他包含java文件的目錄;

需要注意windows下和linux下文件路徑分隔符和文件列表(即-classpath和-sourcepath指定的文件)分隔符的區別:

windows下文件路徑分隔符用 \ ,文件列表分隔符用分號 ;

linux下文件路徑分隔符用 / ,文件列表分隔符用冒號 :

原創文章,作者:HYST,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/139962.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
HYST的頭像HYST
上一篇 2024-10-04 00:23
下一篇 2024-10-04 00:23

相關推薦

  • Python簡單數學計算

    本文將從多個方面介紹Python的簡單數學計算,包括基礎運算符、函數、庫以及實際應用場景。 一、基礎運算符 Python提供了基礎的算術運算符,包括加(+)、減(-)、乘(*)、除…

    編程 2025-04-29
  • Python滿天星代碼:讓編程變得更加簡單

    本文將從多個方面詳細闡述Python滿天星代碼,為大家介紹它的優點以及如何在編程中使用。無論是剛剛接觸編程還是資深程序員,都能從中獲得一定的收穫。 一、簡介 Python滿天星代碼…

    編程 2025-04-29
  • Python海龜代碼簡單畫圖

    本文將介紹如何使用Python的海龜庫進行簡單畫圖,並提供相關示例代碼。 一、基礎用法 使用Python的海龜庫,我們可以控制一個小海龜在窗口中移動,並利用它的「畫筆」在窗口中繪製…

    編程 2025-04-29
  • Python櫻花樹代碼簡單

    本文將對Python櫻花樹代碼進行詳細的闡述和講解,幫助讀者更好地理解該代碼的實現方法。 一、簡介 櫻花樹是一種圖形效果,它的實現方法比較簡單。Python中可以通過turtle這…

    編程 2025-04-28
  • Python大神作品:讓編程變得更加簡單

    Python作為一種高級的解釋性編程語言,一直被廣泛地運用於各個領域,從Web開發、遊戲開發到人工智慧,Python都扮演著重要的角色。Python的代碼簡潔明了,易於閱讀和維護,…

    編程 2025-04-28
  • 用Python實現簡單爬蟲程序

    在當今時代,互聯網上的信息量是爆炸式增長的,其中很多信息可以被利用。對於數據分析、數據挖掘或者其他一些需要大量數據的任務,我們可以使用爬蟲技術從各個網站獲取需要的信息。而Pytho…

    編程 2025-04-28
  • 如何製作一個簡單的換裝遊戲

    本文將從以下幾個方面,為大家介紹如何製作一個簡單的換裝遊戲: 1. 遊戲需求和界面設計 2. 使用HTML、CSS和JavaScript開發遊戲 3. 實現遊戲的基本功能:拖拽交互…

    編程 2025-04-27
  • Guava Limiter——限流器的簡單易用

    本文將從多個維度對Guava Limiter進行詳細闡述,介紹其定義、使用方法、工作原理和案例應用等方面,並給出完整的代碼示例,希望能夠幫助讀者更好地了解和使用該庫。 一、定義 G…

    編程 2025-04-27
  • 2的32次方-1:一個看似簡單卻又複雜的數字

    對於計算機領域的人來說,2的32次方-1(也就是十進位下的4294967295)這個數字並不陌生。它經常被用來表示IPv4地址或者無符號32位整數的最大值。但實際上,這個數字卻包含…

    編程 2025-04-27
  • 製作一個簡單的管理系統的成本及實現

    想要製作一個簡單的管理系統,需要進行技術選型、開發、測試等過程,那麼這個過程會花費多少錢呢?我們將從多個方面來闡述製作一個簡單的管理系統的成本及實現。 一、技術選型 當我們開始思考…

    編程 2025-04-27

發表回復

登錄後才能評論