当前位置:编程学习 > JAVA >>

使用JAVA调用SHELL命令的一个严重问题

    项目需要使用JAVA调用SHELL命令,在测试环境中一切完好,到了生产环境,行不通了!!
    原因是一串命令本来是要到后台去执行的。结果到了生产上没有后台执行!导致运行时间很长,因为如果该SHELL脚本没有后台执行的话,运行时间就是该SHELL脚本运行的时间!
    需要后台执行的命令是这样的:

su - oracle -c "nohup /home/temp/shell.sh > /dev/null&";

    生产上的环境是AIX5.3!在测试环境中,也有AIX5.3,但是这个问题就是重现不了,一到生产上,上面的命令就无法后台执行,老是要执行很长时间,搞得我很郁闷!大家帮帮忙啊

    JAVA代码如下:
/**
 * <pre>
 * Title:         LinuxCodeDispenser.java
 * Project:     RPT2.6
 * Type:        com.sf.module.jobmgmt.biz.LinuxCodeDispenser
 * Author:        255507
 * Create:         2011-12-9 上午10:16:06
 * Copyright:     Copyright (c) 2011
 * Company:        
 * <pre>
 */
package com.sf.module.jobmgmt.dispenser;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.MessageFormat;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import com.sf.module.jobmgmt.domain.JobExecuteParameter;
import com.sf.module.jobmgmt.onlineconfig.OnlineConfigHandler;
import com.sf.module.jobmgmt.util.TaskTransUtils;

/**
 * <pre>
 * 代码分发器的Unix实现,功能是在Unix服务器之间发送并执行相应的代码
 * 条件是两台Unix服务器之间建立了信任关系 
 * </pre>
 * @author 255507
 * @version 1.0, 2011-12-9
 */
public class UnixCodeDispenser implements ICodeDispenser
{
    /**
     * scp /home/leoly/cmd.sh root@10.0.14.111:/home/oracle/
     * 上传文件到UNIX平台的命令
     */
    private final String SCP_COMMAND = "scp {0} {1}@{2}:{3}";

    /**
     * ssh 10.0.14.111 登录到UNIX平台的命令 不提供密码,需要两台机子互信
     */
    private final String LOGIN_COMMAND = "ssh {0}";

    /**
     * chmod +x /home/oracle/2_100002_100000.sh; 增加UNIX平台文件可执行权限的命令
     */
    private final String CHMOD_COMMAND = "chmod +x {0};";

    /**
     * su - oracle -c
     * "nohup /home/oracle/2_100002_100000.sh > /dev/null&";
     * 执行ORACLE的SQL文件的命令
     */
    private final String ORACLE_COMMAND = "su - oracle -c \"nohup {0} > {1}&\";";

    /**
     * exit; 登出命令
     */
    private final String LOGOUT_COMMAND = "exit;";

    private Logger log = Logger.getLogger(UnixCodeDispenser.class);

    /*
     * (非 Javadoc)
     * @see
     * com.sf.module.jobmgmt.biz.ICodeDispenser#sendAndExecCode(java
     * .lang.String)
     */
    public void sendAndExecCode(JobExecuteParameter param)
    {
        ResultService resultService = ExecuteResultService.getInstance();
        long start = System.currentTimeMillis();
        // 先上传文件到服务器,然后登录服务器,增加文件的执行权限,再执行该文件
        if (uploadFile(param, resultService) == EXECUTE_SUCCESS)
        {
            OnlineConfigHandler cfgHandler = OnlineConfigHandler.getInstance();
            String mainCmd = MessageFormat.format(cfgHandler.getString("LOGIN_COMMAND", LOGIN_COMMAND),
                    param.getRemotIp());
            String localPath = param.getLocalFilePath();
            if (localPath.lastIndexOf(File.separator) > 0)
            {
                String fileName = localPath.substring(localPath.lastIndexOf(File.separator) + 1);
                String remotFilepath = param.getRemotFilePath() + File.separator + fileName;
                String chmodCmd = MessageFormat.format(cfgHandler.getString("CHMOD_COMMAND", CHMOD_COMMAND),
                        remotFilepath);
                String oracleCmd = MessageFormat.format(cfgHandler.getString("ORACLE_COMMAND", ORACLE_COMMAND),
                        remotFilepath, "/dev/null");
                String[] cmds = { chmodCmd, oracleCmd, cfgHandler.getString("LOGOUT_COMMAND", LOGOUT_COMMAND) };
                try
                {
                    execCmds(mainCmd, cmds, resultService, param);
                    log.info("################Execute Command Use Time: " + (System.currentTimeMillis() - start) / 1000 + "s");
                }
                catch (IOException e)
                {
                    resultService.doAfterExecute(param, EXECUTE_FAILTURE, e.getMessage());
                    log.error(null, e);
                }
                catch (InterruptedException e)
                {
                    resultService.doAfterExecute(param, EXECUTE_FAILTURE, e.getMessage());
                    log.error(null, e);
                }
            }
            else
            {
                String errorMsg = "Locale file path error:" + localPath;
                log.error(errorMsg);
                resultService.doAfterExecute(param, EXECUTE_FAILTURE, errorMsg);
            }
            
            log.info("################All Execute Command Use Time: " + (System.currentTimeMillis() - start) / 1000 + "s");
        }
    }

    /**
     * <pre>
     * 执行上传文件的命令
     * </pre>
     * @param filePath 文件路径
     * @return
     */
    private int uploadFile(JobExecuteParameter param, ResultService resultService)
    {
        Runtime runtime = Runtime.getRuntime();
        BufferedReader stdReader = null;
        BufferedReader errReader = null;
        int cmdResult = EXECUTE_FAILTURE;
        try
        {
            OnlineConfigHandler cfgHandler = OnlineConfigHandler.getInstance();
            String scpCmdStr = cfgHandler.getString("SCP_COMMAND", SCP_COMMAND);
            String scpCmd = MessageFormat.format(scpCmdStr, param.getLocalFilePath(), param.getRemotUser(),
                    param.getRemotIp(), param.getRemotFilePath());
            log.info("*********************Execute command: " + scpCmd);
            Process process = runtime.exec(scpCmd);
            cmdResult = process.waitFor();
            if (cmdResult != EXECUTE_SUCCESS)
            {
                InputStream errin = process.getErrorStream();
                String errInfo = IOUtils.toString(errin);
                errInfo = "Execute command: [" + scpCmd + "] error! error infomation: " + errInfo;
                log.error(errInfo);
                resultService.doAfterExecute(param, EXECUTE_FAILTURE, errInfo);
            }
        }
        catch (IOException e)
        {
            log.error(null, e);
            resultService.doAfterExecute(param, EXECUTE_FAILTURE, e.getMessage());
        }
        catch (InterruptedException e)
        {
            log.error(null, e);
            resultService.doAfterExecute(param, EXECUTE_FAILTURE, e.getMessage());
        }
        finally
        {
            IOUtils.closeQuietly(errReader);
            IOUtils.closeQuietly(stdReader);
        }

        return cmdResult;
    }

    /**
     * <pre>
     * 执行一系列命令
     * </pre>
     * @param cmds 命令系列
     * @throws IOException
     * @throws InterruptedException
     */
    public void execCmds(String mainCmd, String[] cmds, ResultService resultService, JobExecuteParameter param)
            throws IOException, InterruptedException
    {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec(mainCmd);
        OutputStream os = process.getOutputStream();
        PrintWriter pw = new PrintWriter(os);
        for (String cmd : cmds)
        {
            pw.write(cmd);
            pw.flush();
        }
        pw.close();
        int reslt = process.waitFor();
        // 执行成功的操作:修改任务执行队列表的状态
        if (reslt == EXECUTE_SUCCESS)
        {
            resultService.doAfterExecute(param, EXECUTE_SUCCESS, null);
        }
        else
        {
            InputStream errin = process.getErrorStream();
            String errInfo = IOUtils.toString(errin);
            errInfo = "Execute command: [" + TaskTransUtils.toString(cmds, ", ") + "] error! error infomation: "
                    + errInfo;
            log.error(errInfo);
            IOUtils.closeQuietly(errin);
            resultService.doAfterExecute(param, EXECUTE_FAILTURE, errInfo);
        }
    }
}


请大家为我分析原因,谢谢各位了!
--------------------编程问答-------------------- 那在生產環境相關的錯誤日誌有沒有? --------------------编程问答--------------------
引用 1 楼  的回复:
那在生產環境相關的錯誤日誌有沒有?

没有,这命令本来是后台执行的,现在在生产机子上根本没有后台执行。
错误就是执行时间很长,但不报错 --------------------编程问答--------------------
引用 2 楼  的回复:
引用 1 楼  的回复:

那在生產環境相關的錯誤日誌有沒有?

没有,这命令本来是后台执行的,现在在生产机子上根本没有后台执行。
错误就是执行时间很长,但不报错

這裡也都有log.error(errInfo);記錄啊
能知道是在哪句執行時停滯了嗎? --------------------编程问答-------------------- --------------------编程问答--------------------
引用 3 楼  的回复:
引用 2 楼  的回复:

引用 1 楼  的回复:

那在生產環境相關的錯誤日誌有沒有?

没有,这命令本来是后台执行的,现在在生产机子上根本没有后台执行。
错误就是执行时间很长,但不报错

這裡也都有log.error(errInfo);記錄啊
能知道是在哪句執行時停滯了嗎?


现在可以证明,就是在执行
su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log &"
这句的时候没有转后台执行,导致这句命令需要等待cmd.sh这个文件执行完成后才返回结果
大家帮忙分析下 --------------------编程问答--------------------
引用 3 楼  的回复:
引用 2 楼  的回复:

引用 1 楼  的回复:

那在生產環境相關的錯誤日誌有沒有?

没有,这命令本来是后台执行的,现在在生产机子上根本没有后台执行。
错误就是执行时间很长,但不报错

這裡也都有log.error(errInfo);記錄啊
能知道是在哪句執行時停滯了嗎?

命令本身并没有报错,只是没有转后台而已,所以logger.error(errinfo)获取不到报错信息 --------------------编程问答-------------------- 那重點研究這一句及其上下文
su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log &"

你說的命令本身沒錯,那在測試環境執行成功,而產品環境執行失敗,這兩者有什麽區別呢
不通過java,直接在產品環境的linux下能運行這句嗎? --------------------编程问答--------------------
引用 7 楼  的回复:
那重點研究這一句及其上下文
su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log &"

你說的命令本身沒錯,那在測試環境執行成功,而產品環境執行失敗,這兩者有什麽區別呢
不通過java,直接在產品環境的linux下能運行這句嗎?

直接运行可以,通过JAVA调用就不行 --------------------编程问答--------------------
引用 8 楼  的回复:
引用 7 楼  的回复:

那重點研究這一句及其上下文
su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log &amp;"

你說的命令本身沒錯,那在測試環境執行成功,而產品環境執行失敗,這兩者有什麽區別呢
不通過java,直接在產品環境的linux下能運行這句嗎?

直接运行可以,通过JA……

那研究下測試環境爲什麽通過java調就可以呢,測試環境多了點什麽還是少了點什麽 --------------------编程问答-------------------- su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log 2>&1 &

把错误流和标准输出流合并输入到日志文件中,这样就行了
这屁问题搞了我半个月!! --------------------编程问答--------------------
引用 10 楼  的回复:
su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log 2>&1 &

把错误流和标准输出流合并输入到日志文件中,这样就行了
这屁问题搞了我半个月!!

這樣就能執行了,還是因此看出了問題在哪裡? --------------------编程问答--------------------
引用 11 楼  的回复:
引用 10 楼  的回复:

su - oracle -c "nohup /home/oracle/cmd.sh > /home/oracle/cmd.sh.log 2>&amp;1 &amp;

把错误流和标准输出流合并输入到日志文件中,这样就行了
这屁问题搞了我半个月!!

這樣就能執行了,還是因此看出了問題在哪裡?


不明白啊,可以告诉我吗?我对命令是一知半解的 --------------------编程问答-------------------- 你把你的shell字符串转成字符串数组传到java调用程序中试试
补充:Java ,  Java EE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,