如何在java程序中调用linux命令或者shell脚本

如何在java程序中调用linux命令或者shell脚本,第1张

做到这,主要依赖2个类:Process和Runtime。

首先看一下Process类:

ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,

该实数猛例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、

检查进程的退出状态以及销毁(杀掉)进程的方法。

创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows

上的 Win16/DOS 进程,或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin、stdout 和 stderr)

*** 作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。

父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,

如果读写子进程的输出流或输入流迅速出现失败,则可能导致子如携进程阻塞,甚至产生死锁。

当没有 Process 对象的更多引用时,不是删掉子进程,而是继续异步执行子进程。

对于带有 Process 对象的 Java 进程,没有必要异步或并发执行由 Process 对象表示的进程。

特别需要注意的是

1,创建的子进程没有自己的终端控制台,所有标注 *** 作都会通过三个流

(getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程(父进程可通过这些流判断子进程的执行情况)

2,因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,

则可能导致子进程阻塞,甚至产生死锁

abstract void destroy()

杀掉子进程。

abstract int exitValue()

返回子进程的出口值。根据惯例,值0表示正常终止。

abstract InputStream getErrorStream()

获取子进程的错误流。

abstract InputStream getInputStream()

获取子进程的输入流。

abstract OutputStream getOutputStream()

获取子进程的输出流。

abstract int waitFor()

导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。

如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程。

特别需要注意:如果子进程中的输入流,输出流或错误流中的内容比较多,最好使用缓存(注意上面的情况2)

再来看一下Runtime类:

每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接。可以通过getRuntime方法获取渣毕伏当前运行时环境。

应用程序不能创建自己的Runtime类实例。

介绍几个主要方法:

Process exec(String command)

在单独的进程中执行指定的字符串命令

Process exec(String command, String[] envp)

在指定环境的单独进程中执行指定的字符串命令。

Process exec(String command, String[] envp, File dir)

在有指定环境和工作目录的独立进程中执行指定的字符串命令。

Process exec(String[] cmdarray)

在单独的进程中执行指定命令和变量。

Process exec(String[] cmdarray, String[] envp)

在指定环境的独立进程中执行指定命令和变量。

Process exec(String[] cmdarray, String[] envp, File dir)

在指定环境和工作目录的独立进程中执行指定的命令和变量。

command:一条指定的系统命令。

envp:环境变量字符串数组,其中每个环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为null。

dir:子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为null。

cmdarray:包含所调用命令及其参数的数组。

以下为示例(要打成可执行jar包扔到linux下执行):

public class test {

public static void main(String[] args){

InputStream in = null

try {

Process pro = Runtime.getRuntime().exec(new String[]{"sh",

"/home/test/test.sh","select admin from M_ADMIN",

"/home/test/result.txt"})

pro.waitFor()

in = pro.getInputStream()

BufferedReader read = new BufferedReader(new InputStreamReader(in))

String result = read.readLine()

System.out.println("INFO:"+result)

} catch (Exception e) {

e.printStackTrace()

}

}

}

在这用的是Process exec(String[] cmdarray)这个方法

/home/test/test.sh脚本如下:

#!/bin/sh

#查询sql

SQL=$1

#查询结果保存文件

RESULT_FILE=$2

#数据库连接

DB_NAME=scott

DB_PWD=tiger

DB_SERVER=DB_TEST

RESULT=`sqlplus -S ${DB_NAME}/${DB_PWD}@${DB_SERVER}<<!

set heading off

set echo off

set pages 0

set feed off

set linesize 3000

${SQL}

/

commit

/

!`

echo "${RESULT}" >>${RESULT_FILE}

echo 0

特别需要注意的是,当需要执行的linux命令带有管道符时(例如:ps -ef|grep java),用上面的方法是不行的,解决方式是将需要执行的命令作为参数传给shell

public class Test {

public static void main(String[] args) throws Exception{

String[] cmds = {"/bin/sh","-c","ps -ef|grep java"}

Process pro = Runtime.getRuntime().exec(cmds)

pro.waitFor()

InputStream in = pro.getInputStream()

BufferedReader read = new BufferedReader(new InputStreamReader(in))

String line = null

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

System.out.println(line)

}

}

}

PS:

Runtime.getRuntime().exec()这种调用方式在java虚拟机中是十分消耗资源的,即使命令可以很快的执行完毕,频繁的调用时创建进程消耗十分客观。

java虚拟机执行这个命令的过程是,首先克隆一条和当前虚拟机拥有一样环境变量的进程,再用这个新的进程执行外部命令,最后退出这个进程。频繁的创建对CPU和内存的消耗很大。

几个方案,如Jacl、Feather以及TclBlend。最后选择了TclBlend。原因是:Jacl虽然好处是用纯Java编写的,可不能支持完全的Tcl指令,比如:glob命令的选项都不能使用;Feather虽然号称支持Native Tcl的指令,可安装似乎没有那么方便,版本也没有最近的更新;TclBlend虽然也不是用纯Java程序编写(需要通过JNI去调用C++编写的动态链接库),可基本上还能看到在不停的维护,稍费周折也能让它工作起来。

在使用TclBlend的时候,需要注意的是:如果直接使用下载的二嫌隐冲进制文件,一般都是基于Tcl8.4的。为了能让TclBlend在Java中正常工作,需要先携绝用Dependency Walker检查一下tclblend.dll所依赖的所有文件是否存在。

比如一个实际的问题是,对于xp上安装IE7的使用者,很可能在执行的时候发现动态链接库dwmapi.dll找不到的现象, 此时需要去单独下载该动态链接库文件芹歼放在系统搜索路径中。

1)在linux下写一个.sh文件

(2)文件内容如下:

复制代码

代码如下:

#!/bin/sh

//bash文件头

APP_HOME=/home/blmcrm/crm/A

//要执行的java文件中bin文件的上一个目录,我的目录是/home/blmcrm/crm/A/bin/blm......(后面不写了),总之就是写bin目录前面的部分,因为jar包在bin目录里碰穗毕面,如果不在bin里面,也如此改一下就行

CLASSPATH=$APP_HOME/bin

//bin目录当然是包含jar包的目录啦

for i in "$APP_HOME"/bin/*.jar

//引进所有的jar包,这里用的循环,当然也可以按照这个格式一个一个 写

do

CLASSPATH="$CLASSPATH":"$i" //环境变量就这格式

done

export

CLASSPATH=.:$CLASSPATH//不写这个可能会笑芹说找不到main类

echo

${CLASSPATH}//打印环境变量,可以不写

java -Xms50m -Xmx250m

org.gdh.blm.exec.Syslog_csv

exit(结族睁束) //执行java程序, 其中-Xms50m

-Xmx250m是运行内存什么的设置,后面的是bin目录以后一直到.class的路径,我的是Syslog_csv.class,所以我最后那个是Syslog_csv。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12241915.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-22
下一篇 2023-05-22

发表评论

登录后才能评论

评论列表(0条)

保存