1、判断子进程是否执行结束

有的时候我们用java调用shell之后,之后的操作要在Process子进程正常执行结束的情况下才可以继续,所以我们需要判断Process进程什么时候终止。

Process类提供了waitFor()方法。该方法导致当前线程等待,直到Process线程终止。

Process.waitFor()是有一个int类型返回值的,当返回值为0的时候表Process进程正常终止。否则一般是脚本执行出错了(我遇到的一般是这种情况)。

2、Process.waitFor()导致当前线程阻塞。

有的时候我们发现调用waitFor()方法后,java主线程会一直阻塞在waitFor()处,阻塞的原因是什么呢?分析一下:

Java在执行Runtime.getRuntime().exec(jyName)之后,Linux会创建一个进程,该进程与JVM进程建立三个管道连接,标准输入流、标准输出流、标准错误流,假设linux进程不断

向标准输出流和标准错误流写数据,而JVM却不读取,数据会暂存在linux缓存区,当缓存区存满之后导致该进程无法继续写数据,会僵死,导致java进程会卡死在waitFor()处,

永远无法结束。

解决办法:java进程在waitFor()前不断读取标准输出流和标准错误流:

  1. //jyName  解压脚本路径
  2. String fileName=fileList.get(0).toString().substring(fileList.get(0).toString().lastIndexOf(File.separator)+1);
  3. String  jyName="/etc/zxvf.sh "+fileName;
  4. try {
  5. Process p0 = Runtime.getRuntime().exec(jyName);
  6. //读取标准输出流
  7. BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(p0.getInputStream()));
  8. String line;
  9. while ((line=bufferedReader.readLine()) != null) {
  10. System.out.println(line);
  11. }
  12. //读取标准错误流
  13. BufferedReader brError = new BufferedReader(new InputStreamReader(p0.getErrorStream(), "gb2312"));
  14. String errline = null;
  15. while ((errline = brError.readLine()) != null) {
  16. System.out.println(errline);
  17. }
  18. //waitFor()判断Process进程是否终止,通过返回值判断是否正常终止。0代表正常终止
  19. int c=p0.waitFor();
  20. if(c!=0){
  21. baseRes.put("desc", "软件升级失败:执行zxvf.sh异常终止");
  22. baseRes.setReturnFlag(false);
  23. return baseRes;
  24. }
  25. } catch (IOException e1) {
  26. baseRes.put("desc", "软件升级失败:文件解压失败");
  27. baseRes.setReturnFlag(false);
  28. return baseRes;
  29. } catch (InterruptedException e1) {
  30. baseRes.put("desc", "软件升级失败:文件解压失败");
  31. baseRes.setReturnFlag(false);
  32. return baseRes;
  33. }

也可以在执行Runtime.getRuntime().exec(jyName)之后另外再启动两个线程分别读取标准错误流和标准输出流

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. public class ExcuteThread extends Thread {
  6. private String name;
  7. public ExcuteThread(String name) {
  8. this.name = name;
  9. }
  10. @Override
  11. public void run() {
  12. try {
  13. Process p = Runtime.getRuntime().exec(name);
  14. InputStream fis = p.getInputStream();
  15. final BufferedReader brError = new BufferedReader(
  16. new InputStreamReader(p.getErrorStream(), "gb2312"));
  17. InputStreamReader isr = new InputStreamReader(fis, "gb2312");
  18. final BufferedReader br = new BufferedReader(isr);
  19. Thread t1 = new Thread() {
  20. public void run() {
  21. String line = null;
  22. try {
  23. while ((line = brError.readLine()) != null) {
  24. // System.out.println(line);
  25. }
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. } finally {
  29. try {
  30. if (brError != null)
  31. brError.close();
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }
  37. };
  38. Thread t2 = new Thread() {
  39. public void run() {
  40. String line = null;
  41. try {
  42. while ((line = br.readLine()) != null) {
  43. // System.out.println(line);
  44. }
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. } finally {
  48. try {
  49. if (br != null)
  50. br.close();
  51. } catch (IOException e) {
  52. // TODO Auto-generated catch block
  53. e.printStackTrace();
  54. }
  55. }
  56. }
  57. };
  58. t1.start();
  59. t2.start();
  60. } catch (IOException e1) {
  61. // TODO Auto-generated catch block
  62. e1.printStackTrace();
  63. } finally {
  64. }
  65. }
  66. }

3、shell脚本中有关联脚本,注意路径

就是shell脚本中还要执行其他脚本,这时候就是注意一个路径的问题,这个问题也是我找了好长时间的一个问题。

Process p=Runtime.getRuntime().exec(“/etc/a.sh”)

在Test.java类调用了etc目录下的a.sh脚本, a.sh脚本中执行etc目录下的b.sh脚本,原来我在a.sh脚本中写的是./b.sh。其实这样linux是找不到b.sh的,因为我们执行是在

Test.class目录下调用的/etc/a.sh  所以当a.sh中执行./b.sh的时候他会在Test.class目录下寻找,所以找不到,所以a.sh中要写成/etc/b.sh

4、java连续调用多个脚本

  1. String[] cmd = { "/bin/sh", "-c", "rm -rf /installation/upgrade/ ; mkdir /installation/upgrade/" };
  2. Process p = Runtime.getRuntime().exec(cmd);
  3. p.waitFor();

就是这种数组的方式。

5、java执行.sh脚本文件的时候直接写目录就行,例如这样:Runtime.getRuntime().exec(“/etc/a.sh”)

java 直接执行语句的时候需要加上"/bin/sh"  例如这样:

    1. String name="/bin/sh cd /installation/upgrade/ip89_install_packet";
    2. Process p = Runtime.getRuntime().exec(name);

Java执行shell遇到的各种问题的更多相关文章

  1. Java执行Shell脚本

    Linux 系统下采用 Java 执行 Shell 脚本,直接上代码: package com.smbea.demo; import java.io.BufferedReader; import ja ...

  2. Java执行shell脚本并返回结果两种方法的完整代码

    Java执行shell脚本并返回结果两种方法的完整代码 简单的是直接传入String字符串,这种不能执行echo 或者需要调用其他进程的命令(比如调用postfix发送邮件命令就不起作用) 执行复杂的 ...

  3. 利用java执行shell脚本

    BPMN中存在由系统执行的脚本任务,shell脚本任务也是该系统任务脚本中的一种,利用的也是由java执行shell脚本. 代码中的ProcessBuilder类,为java.lang.Process ...

  4. java 执行shell命令及日志收集避坑指南

    有时候我们需要调用系统命令执行一些东西,可能是为了方便,也可能是没有办法必须要调用.涉及执行系统命令的东西,则就不能做跨平台了,这和java语言的初衷是相背的. 废话不多说,java如何执行shell ...

  5. Android Java执行Shell命令

    最新内容建议直接访问原文:http://www.trinea.cn/android/android-java-execute-shell-commands/ 主要介绍Android或Java应用中如何 ...

  6. Java 执行Shell脚本指令

    一.介绍 有时候我们在Linux中运行Java程序时,需要调用一些Shell命令和脚本.而Runtime.getRuntime().exec()方法给我们提供了这个功能,而且Runtime.getRu ...

  7. java 执行shell命令遇到的坑

    正常来说java调用shell命令就是用 String[] cmdAry = new String[]{"/bin/bash","-c",cmd} Runtim ...

  8. java执行shell脚本并输出执行情况

    1.脚本test.sh,置于/Users/hdwang目录下 #!/bin/sh cd /Users/hdwang echo ls:`ls` ;i<=;i++)); do + ); sleep ...

  9. [Java] Java执行Shell命令

    Methods ProcessBuilder.start() 和 Runtime.exec() 方法都被用来创建一个操作系统进程(执行命令行操作),并返回 Process 子类的一个实例,该实例可用来 ...

随机推荐

  1. Sql Server索引重建

    公司线上数据有几千万数据,有时候索引碎片会导致索引达不到我们的预期查询效率,这个时候将索引重建将会提升一定效率,不过重建的时候一定得晚上用户少的时候,索引重建需要一定时间. 直接贴自动重建索引脚本吧 ...

  2. 一轮冲刺(NABCD)和需求分析

    N我们的创意是为了解决我们测量人员在测量结束后要计算一些数据的问题,当我们观测角度后,有大量的角度需要计算,有时会用到角度与弧度的转换. A我们测量人员知道计算的公式,了解一些c++和c# B我们这个 ...

  3. C++中多维数组传递参数

    在c++自定义函数时我们有时需要传递参数,有时以多维数组作为参数,这里就遇到了多维数组该怎么传值的问题了,首先我们看看一维数组是怎么做的. void print_num(int num[], int ...

  4. Cocos2dx利用intersectsRect函数检测碰撞

    if (sp1->boundingBox().intersectsRect(sp2->boundingBox())) { pLabel->setString(“碰撞飞机爆炸”); } ...

  5. Nginx安装详细指南

    nginx安装环境 nginx是C语言开发,建议在linux上运行,本教程使用Centos6.5作为安装环境.  gcc 安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有g ...

  6. 在MySQL中快速的插入大量测试数据

    很多时候为了测试数据库设计是否恰当,优化SQL语句,需要在表中插入大量的数据,怎么插入大量的数据就是个问题了. 最开始想到的办法就是写一个程序通过一个很大的循环来不停的插入,比如这样: int i = ...

  7. linux自启动tomcat

    第一种方式 1.修改脚本文件rc.local:vim /etc/rc.d/rc.local 这个脚本是使用者自定的开机启动程序,可以在里面添加想在系统启动之后执行的脚本或者脚本执行命令 2.添加如下内 ...

  8. 2018.4.24 快排查找第K大

    import java.util.Arrays; /* 核心思想:利用快排思想,先假定从大到小排序,找枢纽,枢纽会把大小分开它的两边,当枢纽下标等于k时, 即分了k位在它左边或右边,也就是最大或最小的 ...

  9. 学习笔记TF015:加载图像、图像格式、图像操作、颜色

    TensorFlow支持JPG.PNG图像格式,RGB.RGBA颜色空间.图像用与图像尺寸相同(height*width*chnanel)张量表示.通道表示为包含每个通道颜色数量标量秩1张量.图像所有 ...

  10. java 程序编译和运行过程

    java整个编译以及运行的过程相当繁琐,我就举一个简单的例子说明: Java程序从源文件创建到程序运行要经过两大步骤: 1.源文件由编译器编译成字节码(ByteCode): 2.字节码由java虚拟机 ...