背景

java可以通过Runtime来调用其他进程,如cmd命令,shell文件或脚本等。

基本用法

Runtime执行时返回一个Process对象,利用该对象完成脚本执行。下面的例子中,Linux的/home/目录下有一个删除指定日期文件的脚本deletefile.sh,Java调用该脚本的方法如下。

 /**
* 删除指定日期的文件
* @param date yyyy-MM-dd格式
*/
private static void setSystemDate(String date){
Process process = null;
String command1 = "/bin/sh /home/deletefile.sh "+date;
System.out.println(command1);
try {
process = Runtime.getRuntime().exec(command1);
//必须等待该进程结束,否则时间设置就无法生效
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}finally{
if(process!=null){
process.destroy();
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

缓冲区满问题

如果脚本执行过程中产生大量的控制台输出信息,这种信息会被Shell进程输出到内存缓冲区中,而上述用法中作为父进程的java进程并没有处理缓冲区内容,那么就会出现缓冲区满,Java进程挂起的情况。
解决办法是,使用Java线程读取Shell脚本的输出信息。

   public static List<String> executeShell(String shpath, String var){

        //String shpath="/test/test.sh";   // sh 路径
//String var="201102"; // sh 参数
String shellVar = (var==null)?"":var;
String command1 = "chmod 777 " + shpath; // 为 sh 添加权限
String command2 = "/bin/sh " + shpath + " " + shellVar;
final List<String> strList = new ArrayList<String>();
Process process1 = null;
BufferedReader in = null;
try {
process1 = Runtime.getRuntime().exec(command1); // 执行添加权限的命令
process1.waitFor(); // 如果执行多个命令,必须加上
final Process process2 = Runtime.getRuntime().exec(command2); //处理InputStream的线程
new Thread() {
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(process2.getInputStream()));
String line = null;
try{
while((line = in.readLine()) != null) {
strList.add(line);
}
}catch(IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}.start(); //处理ErrorStream的线程
new Thread() {
@Override
public void run(){
BufferedReader err = new BufferedReader(new InputStreamReader(process2.getErrorStream()));
String line = null;
try{
while((line = err.readLine()) != null)
{
strList.add(line);
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
err.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}.start(); process2.waitFor(); } catch (IOException e) { } catch (InterruptedException e) { }finally {
if(in != null){
try {
in.close();
} catch (IOException e) { }
}
if(process1 != null){
process1.destroy();
}
}
return strList;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

线程阻塞问题

如果执行的shell脚本中有等待输入命令,比如more操作,那么在使用java进程读取缓冲区内容的时候,会出现线程阻塞等待的问题。
例如,下面的脚本读取文件内容。

filePath=/home/software.info
softType=$(more $filePath)
echo $softType
  • 1
  • 2
  • 3

上述三行代码很简单地输出了一个文件的内容,而且这个文件很短,只有一行,在Linux下执行没有问题,但是如果用Java调用executeShell方法执行的话,处理InputStream的线程会出现阻塞等待问题,根源在于脚本中的more命令,它会等待控制台的输入,从而导致了Java进程的阻塞。
解决办法就是避免在shell脚本中使用more命令,用cat命令替换即可。

管道命令不执行问题

使用Process执行shell命令时,如果命令中包含管道命令,直接执行会得不到正确结果,解决办法是使用/bin/sh,将/bin/sh放在待执行的shell命令的前面,可保证管道命令的正确执行。

String command1 = "/bin/sh ifconfig | grep if= | awk '{print $1,$6}'";

  • 1
  • 2

启示录

究竟在Java中调用Shell是不是明智的呢?

Java调用Shell问题整理的更多相关文章

  1. Java 调用 shell 脚本详解

    这一年的项目中,有大量的场景需要Java 进程调用 Linux的bash shell 脚本实现相关功能. 从之前的项目中拷贝的相关模块和网上的例子来看,有个别的“陷阱”造成调用shell 脚本在某些特 ...

  2. JAVA调用SHELL事例

    以往一直都是crontab+shell调用java程序,最近需要反过来,使用java调用shell程序,实现定时管理,今天总结一下. 基础内容: java的java.lang.Runtime类提供了e ...

  3. [转载]JAVA调用Shell脚本

    FROM:http://blog.csdn.net/jj12345jj198999/article/details/11891701 在实际项目中,JAVA有时候需要调用C写出来的东西,除了JNI以外 ...

  4. java基础/java调用shell命令和脚本

    一.项目需求: 从某一机构获取证书,证书机构提供小工具,执行.sh脚本即可启动服务,本地调用该服务即可获取证书. 问题:linux服务器启动该服务,不能关闭.一旦关闭,服务即停止. 解决方案:java ...

  5. java调用shell脚本小demo

    复制指定文件cpp.sh: [root@localhost soft]# vim cpp.sh#!/bin/bash name="$1"\cp /home/soft/test/${ ...

  6. java调用shell获取返回值

    转自:http://blog.csdn.net/tengdazhang770960436/article/details/12014839 1.shell文件return.sh echo 1 echo ...

  7. java调用shell脚本,并获得结果集的例子

    /** * 运行shell脚本 * @param shell 需要运行的shell脚本 */ public static void execShell(String shell){ try { Run ...

  8. Java 调用 Shell 命令

    近日项目中有这样一个需求:系统中的外币资金调度完成以后,要将调度信息生成一个Txt文件,然后将这个Txt文件发送到另外一个系统(Kondor)中.生成文件自然使用OutputStreamWirter了 ...

  9. Hadoop概念学习系列之Java调用Shell命令和脚本,致力于hadoop/spark集群(三十六)

    前言 说明的是,本博文,是在以下的博文基础上,立足于它们,致力于我的大数据领域! http://kongcodecenter.iteye.com/blog/1231177 http://blog.cs ...

  10. java 调用shell命令

    原文:http://kongcodecenter.iteye.com/blog/1231177 Java通过SSH2协议执行远程Shell脚本(ganymed-ssh2-build210.jar)   ...

随机推荐

  1. 我在大厂做 CR——为什么建议使用枚举来替换布尔值

    使用枚举替换布尔值主要基于以下几个原因 ● 可读性 ● 可拓展性 ● 安全防控 可读性 我们会定义 boolean 类型(true 或 false)作为方法参数,虽然比较简洁,但有时候参数的含义往往不 ...

  2. C++内存模型实践探索

    前言 C++对象模型是个常见.且复杂的话题,本文基于Itanium C++ ABI通过程序实践介绍了几种 简单C++继承 场景下对象模型,尤其是存在虚函数的场景,并通过图的方式直观表达内存布局.本文展 ...

  3. 自如月租计算 ziroom

    前言 自如的房子月租看似不高,实际上它是收中介费的,加上中介费和未满一年的押金,房租其实非常高. 普通中介费一般收1个月,自如的中介费美名其曰服务费(除了网费想不到有什么用的),一年为1.2个月租金. ...

  4. window平台快速部署syslog服务器

    最近内部测试需要部署一套syslog服务器,网上找了下,无论是linux还是windows,部署均非常麻烦,现在和大家分享一个基于windows平台快速部署syslog服务器的方法 这里用到的工具就是 ...

  5. DRF-Permission组件源码分析及改编源码

    1. 权限组件源码分析 PS:下列源码为了方便理解都进行了简化,只保留了权限相关的代码 由于视图函数中继承了APIView,因此permission_classes可在视图类中进行重写. 注意点: 执 ...

  6. 五分钟掌握Python中配置文件解析器configparser的使用

    ---  好的方法很多,我们先掌握一种  --- [背景] 这里描述的配置文件为自动化用例中使用到的信息,非pytest自动化框架中例如pytest.ini, conftest.py等具有特殊意义的配 ...

  7. winform 音乐播放器

    引言 本次项目目的主要为了熟悉axWindowsMediaPlayer,treeview等控件使用,以及学习I/O操作. 技术栈 C# winform 实现效果 设计与实现 使用TreeView实现音 ...

  8. 【转载】《扩散模型是实时游戏引擎(Diffusion Models Are Real-Time Game Engines)》的论文,向我们展示了世界上第一个完全由神经模型驱动的游戏引擎,GameNGen。这也是历史上首次,AI能在不借助其他游戏引擎的情况下,为玩家生成实时游戏了,并且在单个TPU上速度可以达到每秒20帧

    地址: https://www.youtube.com/watch?v=VniPJII6ak0 8月29号,谷歌DeepMind发布了一篇名为<扩散模型是实时游戏引擎(Diffusion Mod ...

  9. gh-ost工具在线改表过程的详细解析

    gh-ost,是github开源的一款在线修改MySQL表结构的工具https://github.com/github/gh-ost/,它不使用pt-osc的触发器机制,而是使用解析binlog来实现 ...

  10. Java 10大优点—Part4—Java内存模型

    本文由 ImportNew - 靳禹 翻译自 zeroturnaround.如需转载本文,请先参见文章末尾处的转载要求. 在忙着参加在爱沙尼亚进行的 TEDx talk 演讲活动以及在比利时举办的一届 ...