Java ssh 客户端 Jsch 怎么执行 sudo su 后再执行新命令

2022-03-31 21:16:34 +08:00
 leiuu

背景是这样的。

我在本地通过 jsch 对一台远程机器执行命令,但该命令需 sudo 权限。

远程用户,只开放了登录用户的 sudo su 的权限。

导致想执行 sudo 命令需分两步:

sudo su -
docker ps

这里涉及到 session 切换,原生的 Jsch 的 ExecChannel 就用不了。

改为 ChannelShell 。

ChannelShell channel = (ChannelShell) session.openChannel("shell");

OutputStream os = channel.getOutputStream();

os.write(("sudo su - \r").getBytes());
os.flush();
os.write(("docker ps \r").getBytes());
os.flush();
os.write(("exit \r".getBytes());
os.flush();
os.write(("exit \r").getBytes());
os.flush();

但这个命令的返回,是一堆 shell 命令和结果糅合在一起,比较难提取真正的结果。

sudo su -
docker ps
exit
exit
20:51:19  demo@host-a.b.c:~ 

$ sudo su -
20:51:19  root@host-a.b.c:~ 

# docker ps
CONTAINER ID   IMAGE                                                COMMAND                  CREATED        STATUS        PORTS     NAMES
2a3da88c5f8b   ca6e5bfba5a5                                         "/usr/bin/tini -- /u…"   3 days ago     Up 3 days               docker_job_xxx
20:51:19  root@host-a.b.c:~ 

# exit
logout
20:51:19  demo@host-a.b.c:~ 

$ exit
logout

而且如果远程机器换一个 os ,例如是 centos ,则:

Last login: Thu Mar 31 20:27:32 2022 from 192.168.1.2

sudo su -
docker ps
exit
exit
[demo@host-e.f.g ~]$ sudo su -
Last login: Thu Mar 31 14:17:40 CST 2022 on pts/3
[root@host-e.f.g ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
8929e8f93280        img_xxx     "/usr/sbin/init"    5 months ago        Up 5 months                             docker_job_yyy
[root@host-e.f.g ~]# exit
logout
[demo@host-e.f.g ~]$ exit
logout

不同系统或者 terminal 可能会返回格式不同,导致真正想要的结果难以提取。

请教是否有好的解决方法呢?

文档:

http://www.jcraft.com/jsch/

1770 次点击
所在节点    程序员
9 条回复
kekxv
2022-03-31 21:49:40 +08:00
sudo chmod +s docker 路径
comlewin
2022-03-31 22:01:01 +08:00
/**
* 执行单句的命令
* 1 、命令之间使用; 分隔,各个命令的执行不会影响其他命令的执行,各个命令都会执行,但不保证每个命令都执行成功
* 2 、命令之间使用&& 分隔,前面的命令执行成功,才会去执行后面的命令,保证执行过程都是成功的
* 3 、命令之间使用|| 分隔,||是或的意思,只有前面的命令执行失败后才会去执行下一条命令,知道执行成功一条命令为止
*/
public static String execCommand (Session session, String command, String charset) throws JSchException, IOException {
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setPty(true);
InputStream stdout = channelExec.getInputStream();
InputStream stderr = channelExec.getErrStream();
channelExec.setCommand(command);
channelExec.connect();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
StringBuffer sb = new StringBuffer();
byte[] tmp = new byte[1024];
while(true) {
while(stdout.available() > 0) {
int len = stdout.read(tmp, 0, 1024);
if (len < 0 ) {
break;
}
String s_out = new String(tmp, 0, len);
sb.append(s_out);
//System.out.println(s);
}
while(stderr.available() > 0) {
int len = stderr.read(tmp, 0, 1024);
if (len < 0 ) {
break;
}
String s_err = new String(tmp, 0, len);
sb.append(s_err);
//System.out.println(s);
}
break;
}

//sb.append(outinfo);
//sb.append(errinfo);

channelExec.disconnect();
// session 不做断开处理
//session.disconnect();

return sb.toString();
}
Puteulanus
2022-04-01 00:39:01 +08:00
sudo su -c 'docker ps'
这样行吗
biubiuF
2022-04-01 00:43:21 +08:00
sudo -S -p 'password' "+ command
ysc3839
2022-04-01 02:51:58 +08:00
同样建议试试 sudo su -c
实在不行的话,执行命令前后都 echo 随机字符串,然后根据这两段字符串来分割
leiuu
2022-04-01 10:53:36 +08:00
@kekxv 老哥 这个会写操作 不安全

@comlewin 是的 分隔符的方式适用没有 session 切换的场景

@Puteulanus @ysc3839 谢谢 2 位 竟然可以了!

@biubiuF 不知道密码的 不过如果有密码是可行的!
undownding
2022-04-01 17:11:34 +08:00
有没有一种可能,/var/run/docker.sock 可以用 curl 操作?(狗头)
undownding
2022-04-01 17:22:08 +08:00
su -c ' curl --unix-socket /run/docker.sock http://localhost/containers/json'
leiuu
2022-04-01 19:39:29 +08:00
@undownding 老哥 太帅了 奥利给!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/844182

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX