日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java调用shell脚本及注意事项

發(fā)布時間:2024/7/23 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java调用shell脚本及注意事项 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

需求:

get方法下載遠(yuǎn)程zip包,然后zip包解壓,取出第一級目錄再次進(jìn)行壓縮獲取新的壓縮zip包。

問題:

如果選擇使用java代碼的IO流操作,在不確定zip包大小的情況下可能會占用很大的內(nèi)存,所以選擇異步調(diào)用shell腳本來實現(xiàn)這個操作;

介紹:

1、通過ProcessBuilder進(jìn)行調(diào)度

//解決腳本沒有執(zhí)行權(quán)限 ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", scriptPath); Process process = builder.start(); process.waitFor();


2、直接通過系統(tǒng)的Runtime類執(zhí)行shell

? ? ? ? Runtime類封裝了運(yùn)行時的環(huán)境。每個 Java 應(yīng)用程序都有一個 Runtime 類實例,使應(yīng)用程序能夠與其運(yùn)行的環(huán)境相連接。
一般不能實例化一個Runtime對象,應(yīng)用程序也不能創(chuàng)建自己的 Runtime 類實例,但可以通過 getRuntime 方法獲取當(dāng)前Runtime運(yùn)行時對象的引用。
? ? ? 一旦得到了一個當(dāng)前的Runtime對象的引用,就可以調(diào)用Runtime對象的方法去控制Java虛擬機(jī)的狀態(tài)和行為。?

//SHELL_FILE_DIR + RUNNING_SHELL_FILE為腳本的全路徑,后面?zhèn)鬟f給shell腳本多個參數(shù)用空格分隔 Sting cmd = SHELL_FILE_DIR + RUNNING_SHELL_FILE + " "+param1+" "+param2+" "+param3 //RunTime執(zhí)行腳本 Process ps = Runtime.getRuntime().exec(cmd); //waitFor等待shell運(yùn)行完,返回值如果為0,則表明正常運(yùn)行完 int execStatus = ps.waitFor();


遇到的問題:

1、沒權(quán)限運(yùn)行。通過ProcessBuilder來設(shè)置文件的權(quán)限

//解決腳本沒有執(zhí)行權(quán)限,scriptPath為腳本全路徑 ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", scriptPath); Process process = builder.start(); process.waitFor();


2、調(diào)用shell腳本提示:No such file or directory

原因:文件格式不正確導(dǎo)致,在windows下編寫的sh文件,文件是DOS格式。使用:set ff=unix 強(qiáng)制將文件轉(zhuǎn)換為unix格式。

具體操作:

vim模式打開這個shell腳本,查看編碼格式后設(shè)置成unix編碼,輸入:set ff?,查看格式是否是fileformat=unix;如果不是,設(shè)置成unix

:set ff=unix后保存(:wq)即可。

3、shell腳本輸出太大,程序卡死問題

? ? ? ? Java在執(zhí)行Runtime.getRuntime().exec(command)之后,Linux會創(chuàng)建一個進(jìn)程,該進(jìn)程與JVM進(jìn)程建立三個管道連接,標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流、標(biāo)準(zhǔn)錯誤流。

? ? ? ? 當(dāng)標(biāo)準(zhǔn)輸出流或標(biāo)準(zhǔn)錯誤流非常龐大的時候,會出現(xiàn)調(diào)用waitFor方法卡死的bug。真實的環(huán)境中,當(dāng)標(biāo)準(zhǔn)輸出在10000行左右的時候,就會出現(xiàn)卡死的情況。

原因分析:假設(shè)linux進(jìn)程不斷向標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯誤流寫數(shù)據(jù),而JVM卻不讀取,數(shù)據(jù)會暫存在linux緩存區(qū),當(dāng)緩存區(qū)存滿之后導(dǎo)致該進(jìn)程無法繼續(xù)寫數(shù)據(jù),會僵死,導(dǎo)致java進(jìn)程會卡死在waitFor()處,永遠(yuǎn)無法結(jié)束。

解決方式:由于標(biāo)準(zhǔn)輸出和錯誤輸出都會向Linux緩存區(qū)寫數(shù)據(jù),而腳本如何輸出這兩種流是Java端不能確定的。為了不讓shell腳本的子進(jìn)程卡死,這兩種輸出需要分別讀取,而且不能互相影響。所以必須新開兩個線程來進(jìn)行讀取。

new Thread() { ?public void run() { ?BufferedReader br1 = new BufferedReader(new InputStreamReader(is1)); ?try { ?String line1 = null; ?while ((line1 = br1.readLine()) != null) { ?if (line1 != null){} ?} ?} catch (IOException e) { ?e.printStackTrace(); ?} ?finally{ ?try { ?is1.close(); ?} catch (IOException e) { ?e.printStackTrace(); ?} ?} ?} ?}.start(); ?new Thread() { ??public void ?run() { ??BufferedReader br2 = new ?BufferedReader(new ?InputStreamReader(is2)); ??try { ??String line2 = null ; ??while ((line2 = br2.readLine()) != ?null ) { ??if (line2 != null){} ?} ??} catch (IOException e) { ??e.printStackTrace(); ?} ??finally{ ?try { ?is2.close(); ?} catch (IOException e) { ?e.printStackTrace(); ?} ?} ?} ??}.start();

下面提供工具類和自己的shell腳本:

工具類:

import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.io.*; import java.util.Arrays;public class ShellCommandUtils {/** 日志*/private final static Logger logger = LoggerFactory.getLogger(ShellCommandUtils.class);/*** @Description: 執(zhí)行shell** @param scriptPath :腳本路徑* @param param 腳本參數(shù)* @Return: void* @Date: 2019/3/22?*/public static int execShell(String scriptPath, String... param) {logger.info("調(diào)用處理壓縮包的shell腳本,params=" + param.toString());Arrays.stream(param).forEach(item-> logger.info(item));//執(zhí)行結(jié)果int result = 1;try {String[] cmd = new String[]{scriptPath};//為了解決參數(shù)中包含空格cmd = (String[]) ArrayUtils.addAll(cmd, param);logger.info("調(diào)用處理壓縮包的shell腳本,cmd=" + cmd.toString());Arrays.stream(cmd).forEach(item-> logger.info(item));logger.info("解決腳本沒有執(zhí)行權(quán)限邏輯start");//解決腳本沒有執(zhí)行權(quán)限ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", scriptPath);Process process = builder.start();process.waitFor();logger.info("解決腳本沒有執(zhí)行權(quán)限邏輯end");logger.info("開始執(zhí)行runtime的腳本start");Process ps = Runtime.getRuntime().exec(cmd);logger.info("把緩沖區(qū)讀出來打log ?start");//處理InputStream的線程,獲取進(jìn)程的標(biāo)準(zhǔn)輸入流final InputStream is1 = ps.getInputStream();//獲取進(jìn)城的錯誤流final InputStream is2 = ps.getErrorStream();//啟動兩個線程,一個線程負(fù)責(zé)讀標(biāo)準(zhǔn)輸出流,另一個負(fù)責(zé)讀標(biāo)準(zhǔn)錯誤流new Thread() {public void run() {BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));try {String line1 = null;while ((line1 = br1.readLine()) != null) {if (line1 != null){}}} catch (IOException e) {e.printStackTrace();}finally{try {is1.close();} catch (IOException e) {e.printStackTrace();}}}}.start();new Thread() {public void ?run() {BufferedReader br2 = new ?BufferedReader(new ?InputStreamReader(is2));try {String line2 = null ;while ((line2 = br2.readLine()) != ?null ) {if (line2 != null){}}} catch (IOException e) {e.printStackTrace();}finally{try {is2.close();} catch (IOException e) {e.printStackTrace();}}}}.start();//等待shell腳本結(jié)果int execStatus = ps.waitFor();logger.info("執(zhí)行runtime的腳本end");logger.info("shell腳本執(zhí)行結(jié)果--execStatus ="+execStatus);result = execStatus;logger.info("返回值為result=" + result);} catch (Exception e) {logger.error("調(diào)用處理壓縮包的shell出現(xiàn)異常!", e);}return result;}}


shell腳本:

#!/bin/sh #處理壓縮包 fileName=$1 url=$2 homePath=$3#開始處理數(shù)據(jù)邏輯 echo fileName=$fileName, url=$url, homePath=$homePath#判斷參數(shù)不為空 if [ ?-n "$fileName" ]; ?then?if [ ?-n "$url" ]; then#0.cd到對應(yīng)目錄cd $homePath#1.調(diào)用get方法獲取zip包并下載到本地wget -O $fileName.zip $url#2.解壓zip包unzip $fileName.zip#3.刪除zip包rm -f $fileName.zip#4.進(jìn)入解壓完的文件夾cd $fileName#5.壓縮當(dāng)前文件夾下所有文件為指定文件名的zipzip -r ../$fileName.zip ./*#6.刪除之前解壓的文件夾rm -rf $homePath$fileNamefi fiecho "deal package end"

總結(jié)

以上是生活随笔為你收集整理的java调用shell脚本及注意事项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。