001package net.gdface.utils;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.InputStreamReader;
006import java.io.LineNumberReader;
007import java.util.ArrayList;
008import java.util.Arrays;
009import java.util.Collections;
010import java.util.List;
011import java.util.logging.Logger;
012
013/**
014 * linux命令行执行器
015 * @author guyadong
016 *
017 */
018public class CmdExecutor{
019        private static final Logger logger = Logger.getLogger(CmdExecutor.class.getSimpleName());
020        private static final String SUDO_CMD = "sudo";
021        private static final String SHELL_NAME = "/bin/bash";
022        private static final String SHELL_PARAM = "-c";
023        private static final String REDIRECT = "2>&1";
024        /** 执行 sudo 的密码 */
025        private final String sudoPassword;
026        /** 是否显示命令内容及输出 */
027        private boolean verbose=true;
028        /** 是否错误输出重定向 */
029        private boolean errRedirect = true;
030        /** 是否同步,主线程是否等待命令执行结束 */
031        private boolean sync = true;
032        /** 执行多条命令时的命令分隔符 */
033        private String cmdSeparator = " && ";
034        private List<String> cmds = new ArrayList<String>(16);
035        public static CmdExecutor builder(){
036                return new CmdExecutor();
037        }
038        public static CmdExecutor builder(String sudoPasword){
039                return new CmdExecutor(sudoPasword);
040        }
041        protected CmdExecutor(){
042                this(null);
043        }
044        protected CmdExecutor(String sudoPasword){
045                this.sudoPassword = sudoPasword;
046        }
047        public CmdExecutor verbose(boolean verbose){
048                this.verbose = verbose;
049                return this;
050        }
051        public CmdExecutor errRedirect(boolean errRedirect){
052                this.errRedirect = errRedirect;
053                return this;
054        }
055        public CmdExecutor sync(boolean sync){
056                this.sync = sync;
057                return this;
058        }
059        public CmdExecutor cmdSeparator(String cmdSeparator){
060                if(null != cmdSeparator && !cmdSeparator.isEmpty()){
061                        this.cmdSeparator = cmdSeparator;
062                }
063                return this;
064        }
065        private String getRedirect(){
066                return errRedirect ? REDIRECT : "";
067        }
068        /**
069         * 添加一条需要sudo执行的命令
070         * @param cmd 要执行的命令(字符串中不需要有sudo)
071         * @return
072         */
073        public CmdExecutor sudoCmd(String cmd){
074                if(null != cmd && 0 != cmd.length()){
075                        if(null == sudoPassword){
076                                cmds.add(String.format("%s %s %s",SUDO_CMD,cmd,getRedirect()));                                 
077                        }else{
078                                cmds.add(String.format("echo '%s' | %s %s %s",sudoPassword,SUDO_CMD,cmd,getRedirect()));
079                        }                                       
080                }
081                return this;
082        }
083        /**
084         * 添加一条普通命令
085         * @param cmd
086         * @return
087         */
088        public CmdExecutor cmd(String cmd){
089                if(null != cmd && 0 != cmd.length()){
090                        cmds.add(String.format("%s %s",cmd,getRedirect()));                                     
091                }
092                return this;
093        }
094        private List<String> build(){
095                return cmds.isEmpty()
096                                ? Collections.<String>emptyList()
097                                : Arrays.asList(SHELL_NAME,SHELL_PARAM,join(cmds,cmdSeparator));
098        }
099    private static String join(List<String> strs,String separator) {
100        StringBuffer buffer = new StringBuffer();
101        for(int i=0;i<strs.size();++i){
102                if(i>0){
103                        buffer.append(separator);
104                }
105            buffer.append(strs.get(i));
106        }
107        return buffer.toString();
108    }
109    /**
110     * 将{@link InputStream}中所有内容输出到{@link StringBuffer}
111     * @param in
112     * @return
113     * @throws IOException
114     */
115    private static void toBuffer(InputStream in,StringBuffer buffer) throws IOException{
116        if(null == in || null == buffer){
117                return ;
118        }
119                InputStreamReader ir = new InputStreamReader(in);
120                LineNumberReader input = new LineNumberReader(ir);
121                try{
122                        String line;
123                        while ((line = input.readLine()) != null) {
124                                buffer.append(line).append("\n");
125                        }
126                }finally{
127                        input.close();
128                }
129    }
130    /** 
131     * 调用{@link Runtime#exec(String[])}执行命令 
132     * @return 返回输出结果 
133     */
134        public String exec() throws IOException{
135                StringBuffer outBuffer = new StringBuffer();
136                exec(outBuffer,null);
137                return outBuffer.toString();
138        }
139        /**
140         * 调用{@link Runtime#exec(String[])}执行命令 
141         * @param outBuffer 标准输出
142         * @param errBuffer 错误信息输出
143         * @throws IOException
144         */
145        public void exec(StringBuffer outBuffer,StringBuffer errBuffer) throws IOException{
146                List<String> cmdlist = build();
147                if(!cmdlist.isEmpty()){
148                        if(verbose){
149                                logger.info(join(cmdlist," "));
150                        }
151                        Process process = Runtime.getRuntime().exec(cmdlist.toArray(new String[cmdlist.size()]));
152                        if(sync){
153                                try {
154                                        process.waitFor();
155                                } catch (InterruptedException e) {
156                                }
157                        }
158                        toBuffer(process.getInputStream(),outBuffer);
159                        toBuffer(process.getErrorStream(),errBuffer);
160                }
161        }
162}