专栏首页10km的专栏java:执行linux sudo命令

java:执行linux sudo命令

版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/78913746

我们知道java中执行控制台命令,都是通过 Runtime.exec系列方法。 如果要执行root权限的命令需要用到sudo,需要输入sudo密码,这个也好解决,使用echo可以向sudo输入密码,同时sudo要加-S参数指定从标准输入读取密码,示例如下:

echo ‘sudopassword’ | sudo -S cat /etc/profile

但是在java中通过 Runtime.exec方法执行上面的命令,还是会无效。错误提示可能是。

sudo:抱歉,您必须拥有一个终端来执行 sudo sudo: sorry, you must have a tty to run sudo sudo:没有终端存在,且未指定 askpass 程序 sudo: no tty present and no askpass program specified

解决这个问题需要修改/etc/sudoers

# 给 sudoers 增加写权限
sudo chmod +w /etc/sudoers
# 编辑 sudoers
vi /etc/sudoers

找到 Defaults requiretty改为Defaults !requiretty或者直接注释掉#Defaults requiretty 找到Defaults !visiblepw改为Defaults visiblepw或者增一行 Defaults visiblepw 如下图。

修改后 wq保存,记得要sudo chmod -w /etc/sudoers删除写权限

为了简化sudo命令的执行,我封装一了个CmdExceuor类,允许执行多条命令。

代码仓库地址: https://gitee.com/l0km/common-java/blob/master/common-base/src/main/java/net/gdface/utils/CmdExecutor.java

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

/**
 * linux命令行执行器
 * @author guyadong
 *
 */
public class CmdExecutor{
    private static final Logger logger = Logger.getLogger(CmdExecutor.class.getSimpleName());
    private static final String SUDO_CMD = "sudo";
    private static final String SHELL_NAME = "/bin/bash";
    private static final String SHELL_PARAM = "-c";
    private static final String REDIRECT = "2>&1";
    /** 执行 sudo 的密码 */
    private final String sudoPassword;
    /** 是否显示命令内容及输出 */
    private boolean verbose=true;
    /** 是否错误输出重定向 */
    private boolean errRedirect = true;
    /** 是否同步,主线程是否等待命令执行结束 */
    private boolean sync = true;
    /** 执行多条命令时的命令分隔符 */
    private String cmdSeparator = " && ";
    private List<String> cmds = new ArrayList<String>(16);
    public static CmdExecutor builder(){
        return new CmdExecutor();
    }
    public static CmdExecutor builder(String sudoPasword){
        return new CmdExecutor(sudoPasword);
    }
    protected CmdExecutor(){
        this(null);
    }
    protected CmdExecutor(String sudoPasword){
        this.sudoPassword = sudoPasword;
    }
    public CmdExecutor verbose(boolean verbose){
        this.verbose = verbose;
        return this;
    }
    public CmdExecutor errRedirect(boolean errRedirect){
        this.errRedirect = errRedirect;
        return this;
    }
    public CmdExecutor sync(boolean sync){
        this.sync = sync;
        return this;
    }
    public CmdExecutor cmdSeparator(String cmdSeparator){
        if(null != cmdSeparator && !cmdSeparator.isEmpty()){
            this.cmdSeparator = cmdSeparator;
        }
        return this;
    }
    private String getRedirect(){
        return errRedirect ? REDIRECT : "";
    }
    /**
     * 添加一条需要sudo执行的命令
     * @param cmd 要执行的命令(字符串中不需要有sudo)
     * @return
     */
    public CmdExecutor sudoCmd(String cmd){
        if(null != cmd && 0 != cmd.length()){
            if(null == sudoPassword){
                cmds.add(String.format("%s %s %s",SUDO_CMD,cmd,getRedirect()));                 
            }else{
                cmds.add(String.format("echo '%s' | %s %s %s",sudoPassword,SUDO_CMD,cmd,getRedirect()));
            }                   
        }
        return this;
    }
    /**
     * 添加一条普通命令
     * @param cmd
     * @return
     */
    public CmdExecutor cmd(String cmd){
        if(null != cmd && 0 != cmd.length()){
            cmds.add(String.format("%s %s",cmd,getRedirect()));                 
        }
        return this;
    }
    private List<String> build(){
        return cmds.isEmpty()
                ? Collections.<String>emptyList()
                : Arrays.asList(SHELL_NAME,SHELL_PARAM,join(cmds,cmdSeparator));
    }
    private static String join(List<String> strs,String separator) {
        StringBuffer buffer = new StringBuffer();
        for(int i=0;i<strs.size();++i){
            if(i>0){
                buffer.append(separator);
            }
            buffer.append(strs.get(i));
        }
        return buffer.toString();
    }
    /**
     * 将{@link InputStream}中所有内容输出到{@link StringBuffer}
     * @param in
     * @return
     * @throws IOException
     */
    private static void toBuffer(InputStream in,StringBuffer buffer) throws IOException{
        if(null == in || null == buffer){
            return ;
        }
        InputStreamReader ir = new InputStreamReader(in);
        LineNumberReader input = new LineNumberReader(ir);
        try{
            String line;
            while ((line = input.readLine()) != null) {
                buffer.append(line).append("\n");
            }
        }finally{
            input.close();
        }
    }
    /** 
     * 调用{@link Runtime#exec(String[])}执行命令 
     * @return 返回输出结果 
     */
    public String exec() throws IOException{
        StringBuffer outBuffer = new StringBuffer();
        exec(outBuffer,null);
        return outBuffer.toString();
    }
    /**
     * 调用{@link Runtime#exec(String[])}执行命令 
     * @param outBuffer 标准输出
     * @param errBuffer 错误信息输出
     * @throws IOException
     */
    public void exec(StringBuffer outBuffer,StringBuffer errBuffer) throws IOException{
        List<String> cmdlist = build();
        if(!cmdlist.isEmpty()){
            if(verbose){
                logger.info(join(cmdlist," "));
            }
            Process process = Runtime.getRuntime().exec(cmdlist.toArray(new String[cmdlist.size()]));
            if(sync){
                try {
                    process.waitFor();
                } catch (InterruptedException e) {
                }
            }
            toBuffer(process.getInputStream(),outBuffer);
            toBuffer(process.getErrorStream(),errBuffer);
        }
    }
}

使用示例如下:

import static org.junit.Assert.*;

public class CmdExecutorTest {

    @Test
    public void test() {
        try {
            // 创建一个CmdExecutor实例,通过sudoCmd或cmd添加要执行的命令,最后调用exec执行。
            String out = CmdExecutor.builder("sudopassword")
            .errRedirect(false)
            .sudoCmd("date -s '2016-12-27 23:23:23'")// 修改系统时间
            .sudoCmd("clock -w")
            .sudoCmd("cat /etc/sysconfig/network")
            .cmd("date")
            .sudoCmd("ntpdate -u time.windows.com")// 系统时间同步
            .exec();
            System.out.println(out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

代码仓库地址: https://gitee.com/l0km/common-java/blob/master/common-base/src/test/java/net/gdface/common/CmdExecutorTest.java

参考资料

《解决sudo: sorry, you must have a tty to run sudo》http://blog.csdn.net/breezehappy/article/details/38895375

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • linux shll:sudo的相关使用

    判断当前是否有sudo权限可以用sudo -v返回0为sudo user,否则不是。 使用示例:

    用户1148648
  • java:多网卡环境下获取MAC地址

    JDK6以后 java.net.NetworkInterface提供了完整的方法用于获取网络设备信息。 调用 NetworkInterface.getNet...

    用户1148648
  • linux gnu c 复制文件实例(open,close,creat,read,write)

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • AOJ1370: Hidden Anagrams(hash)

    attack
  • Serial Port Debug on EBox4300

      自从上次安装了EBox4300的开发环境以后,就忙着其他事情,没有来得及做点应用。今天做了一个串口通信的应用,发上来和大家分享一下。   串口是设备调试中经...

    ShiJiong
  • 【STM32F429】第16章 ThreadX GUIX窗口局部刷新的实现

    本章节为大家讲解GUIX窗口的局部或全局刷新的实现。这个功能用的到地方也比较多,比如2D图形的更新,音乐频谱的更新,2D图像的更新等场合都会用到这个功能。

    armfly
  • 【STM32H7】第16章 ThreadX GUIX窗口局部刷新的实现

    最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

    armfly
  • Activiti7入门Demo

    需要注意的是idea64.exe.vmoptions 这个文件可能有多个,别改错了。

    诺浅
  • 面试题 | 《Java常见面试题集 》- 第一套

    Java中String不是基本类型,String 类型默认初始为 Null,即为空未分配对象;如果使用String类型定义的变量并且有返回值,则必须进行初始化;

    码神联盟
  • RCE的Bypass与骚姿势总结

    前言:关于RCE的Bypass,我们应该从哪些角度开展呢。要知道怎么绕过,我们就得知道防火墙的过滤规则才行。那我们想想,在利用RCE漏洞的时候,我们当然想用ca...

    天钧

扫码关注云+社区

领取腾讯云代金券