java jsch 调用shell_java 远程执行Shell命令-通过Jsch连接

JSch是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等,当然你也可以集成它的功能到你自己的应用程序。

本文只介绍如何使用JSch实现的SFTP功能。

SFTP是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。SFTP 为 SSH的一部份,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。(来自百度的解释)

要使用JSch,需要下载它的jar包,请从官网下载它:http://www.jcraft.com/jsch/

ChannelSftp类是JSch实现SFTP核心类,它包含了所有SFTP的方法,如:

put(): 文件上传

get(): 文件下载

cd(): 进入指定目录

ls(): 得到指定目录下的文件列表

rename(): 重命名指定文件或目录

rm(): 删除指定文件

mkdir(): 创建目录

rmdir(): 删除目录

等等(这里省略了方法的参数,put和get都有多个重载方法,具体请看源代码,这里不一一列出。)

JSch支持三种文件传输模式:

传输模式名

描述

OVERWRITE

完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。

RESUME

恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,则会从上一次中断的地方续传。

APPEND

追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。

1、引入jar包

com.jcraft

jsch

0.1.54

2、实际例子

package com.bluemoon.executor.core.executor;

import com.bluemoon.executor.core.log.XxlJobLogger;

import com.jcraft.jsch.*;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.*;

import java.nio.charset.Charset;

public class JSchExecutor {

private static Logger log = LoggerFactory.getLogger(JSchExecutor.class);

private String charset = "UTF-8"; // 设置编码格式

private String user; // 用户名

private String passwd; // 登录密码

private String host; // 主机IP

private int port = 22; //默认端口

private JSch jsch;

private Session session;

private ChannelSftp sftp;

/**

*

* @param user 用户名

* @param passwd 密码

* @param host 主机IP

*/

public JSchExecutor(String user, String passwd, String host ) {

this.user = user;

this.passwd = passwd;

this.host = host;

}

/**

*

* @param user 用户名

* @param passwd 密码

* @param host 主机IP

*/

public JSchExecutor(String user, String passwd, String host , int port ) {

this.user = user;

this.passwd = passwd;

this.host = host;

this.port = port;

}

/**

* 连接到指定的IP

*

* @throws JSchException

*/

public void connect() throws JSchException {

jsch = new JSch();

session = jsch.getSession(user, host, port);

session.setPassword(passwd);

java.util.Properties config = new java.util.Properties();

config.put("StrictHostKeyChecking", "no");

session.setConfig(config);

session.connect();

Channel channel = session.openChannel("sftp");

channel.connect();

sftp = (ChannelSftp) channel;

log.info("连接到SFTP成功。host: " + host);

}

/**

* 关闭连接

*/

public void disconnect(){

if (sftp != null && sftp.isConnected()) {

sftp.disconnect();

}

if(session != null && session.isConnected()){

session.disconnect();

}

}

/**

* 执行一条命令

*/

public int execCmd(String command) throws Exception{

XxlJobLogger.log( "开始执行命令:" + command);

int returnCode = -1;

BufferedReader reader = null;

Channel channel = null;

channel = session.openChannel("exec");

((ChannelExec) channel).setCommand(command);

channel.setInputStream(null);

((ChannelExec) channel).setErrStream(System.err);

InputStream in = channel.getInputStream();

reader = new BufferedReader(new InputStreamReader(in));//中文乱码貌似这里不能控制,看连接的服务器的

channel.connect();

System.out.println("The remote command is: " + command);

String buf ;

while ((buf = reader.readLine()) != null) {

XxlJobLogger.log(buf);

}

reader.close();

// Get the return code only after the channel is closed.

if (channel.isClosed()) {

returnCode = channel.getExitStatus();

}

XxlJobLogger.log( "Exit-status:" + returnCode );

/* StringBuffer buf = new StringBuffer( 1024 );

byte[] tmp = new byte[ 1024 ];

while ( true ) {

while ( in.available() > 0 ) {

int i = in.read( tmp, 0, 1024 );

if ( i < 0 ) break;

buf.append( new String( tmp, 0, i ) );

}

if ( channel.isClosed() ) {

res = channel.getExitStatus();

XxlJobLogger.log( "Exit-status:" + res );

System.out.println( "Exit-status:" + res );

break;

}

TimeUnit.MILLISECONDS.sleep(100);

}

XxlJobLogger.log( buf.toString() );*/

channel.disconnect();

return returnCode;

}

/**

* 执行相关的命令

*/

public void execCmd() {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

String command = "";

BufferedReader reader = null;

Channel channel = null;

try {

while ((command = br.readLine()) != null) {

channel = session.openChannel("exec");

((ChannelExec) channel).setCommand(command);

channel.setInputStream(null);

((ChannelExec) channel).setErrStream(System.err);

channel.connect();

InputStream in = channel.getInputStream();

reader = new BufferedReader(new InputStreamReader(in,

Charset.forName(charset)));

String buf = null;

while ((buf = reader.readLine()) != null) {

System.out.println(buf);

}

}

} catch (IOException e) {

e.printStackTrace();

} catch (JSchException e) {

e.printStackTrace();

} finally {

try {

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

channel.disconnect();

}

}

/**

* 上传文件

*/

public void uploadFile(String local,String remote) throws Exception {

File file = new File(local);

if (file.isDirectory()) {

throw new RuntimeException(local + " is not a file");

}

InputStream inputStream = null;

try {

String rpath = remote.substring(0,remote.lastIndexOf("/")+1);

if (!isDirExist(rpath)){

createDir(rpath);

}

inputStream = new FileInputStream(file);

sftp.setInputStream(inputStream);

sftp.put(inputStream, remote);

} catch (Exception e) {

throw e;

}finally{

if(inputStream != null){

inputStream.close();

}

}

}

/**

* 下载文件

*/

public void downloadFile(String remote,String local) throws Exception{

OutputStream outputStream = null;

try {

sftp.connect(5000);

outputStream = new FileOutputStream(new File(local));

sftp.get(remote, outputStream);

outputStream.flush();

} catch (Exception e) {

throw e;

}finally{

if(outputStream != null){

outputStream.close();

}

}

}

/**

* 移动到相应的目录下

* @param pathName 要移动的目录

* @return

*/

public boolean changeDir(String pathName){

if(pathName == null || pathName.trim().equals("")){

log.debug("invalid pathName");

return false;

}

try {

sftp.cd(pathName.replaceAll("\\\\", "/"));

log.debug("directory successfully changed,current dir=" + sftp.pwd());

return true;

} catch (SftpException e) {

log.error("failed to change directory",e);

return false;

}

}

/**

* 创建一个文件目录,mkdir每次只能创建一个文件目录

* 或者可以使用命令mkdir -p 来创建多个文件目录

*/

public void createDir(String createpath) {

try {

if (isDirExist(createpath)) {

sftp.cd(createpath);

return;

}

String pathArry[] = createpath.split("/");

StringBuffer filePath = new StringBuffer("/");

for (String path : pathArry) {

if (path.equals("")) {

continue;

}

filePath.append(path + "/");

if (isDirExist(filePath.toString())) {

sftp.cd(filePath.toString());

} else {

// 建立目录

sftp.mkdir(filePath.toString());

// 进入并设置为当前目录

sftp.cd(filePath.toString());

}

}

sftp.cd(createpath);

} catch (SftpException e) {

throw new RuntimeException("创建路径错误:" + createpath);

}

}

/**

* 判断目录是否存在

* @param directory

* @return

*/

public boolean isDirExist(String directory)

{

boolean isDirExistFlag = false;

try

{

SftpATTRS sftpATTRS = sftp.lstat(directory);

isDirExistFlag = true;

return sftpATTRS.isDir();

}

catch (Exception e)

{

if (e.getMessage().toLowerCase().equals("no such file"))

{

isDirExistFlag = false;

}

}

return isDirExistFlag;

}

}

3、用法

public static void main(String[] args) {

JSchExecutor jSchUtil = new JSchExecutor( "user", "password#","192.168.243.21");

try {

jSchUtil.connect();

jSchUtil.uploadFile("C:\\data\\applogs\\bd-job\\jobhandler\\2020-03-07\\employee.py","/data/applogs/bd-job-777/jobhandler/2018-09-15/employee.py");

//jSchUtil.execCmd("python /data/bluemoon/kettle/runScript/ods/fact_org_employee.py 'so you is wahek 哈哈哈快递放假塑料袋放进了'");

jSchUtil.execCmd("python /data/applogs/bd-job/jobhandler/gluesource/employee.py 中文名称");

//jSchUtil.execCmd("cat /data/applogs/bd-job/jobhandler/test");

} catch (Exception e) {

e.printStackTrace();

}finally {

jSchUtil.disconnect();

}

}

4、实时返回打印的日志

在实际开发中,需要执行一个python文档,里面含有多条的python语句,可能耗时1个小时才能执行完,这种情况需要能够实时的返回日志信息,看看python到底执行到哪一步。

使用ChannelShell可与服务器保持连接状态,可交互信息

用法:

/**

* 实时打印日志信息

*/

public int shellCmd(String command) throws Exception{

XxlJobLogger.log( "开始执行命令:" + command);

int returnCode = -1;

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

InputStream in = channel.getInputStream();

channel.setPty(true);

channel.connect();

OutputStream os = channel.getOutputStream();

os.write((command + "\r\n").getBytes());

os.write("exit\r\n".getBytes());

os.flush();

XxlJobLogger.log("The remote command is:{}" ,command);

byte[] tmp=new byte[1024];

while(true) {

while (in.available() > 0) {

int i = in.read(tmp, 0, 1024);

if (i < 0) break;

XxlJobLogger.log(new String(tmp, 0, i));

}

if (channel.isClosed()) {

if (in.available() > 0) continue;

returnCode = channel.getExitStatus();

XxlJobLogger.log("exit-status: " + channel.getExitStatus());

break;

}

try{Thread.sleep(1000);}catch(Exception ee){}

}

os.close();

in.close();

channel.disconnect();

session.disconnect();

return returnCode;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!针对您的问题,我可以给出以下解答: Java JSch 是一个用于远程执行命令和传输文件的 Java 库,通过 JSch,我们可以在 Java 应用程序中连接远程主机,并执行远程主机上的命令。 针对您的问题,如果您在使用 Java JSch 调用 shell 脚本时,脚本执行后立即退出,可能是因为您的 Java 程序没有等待 shell 脚本执行完毕就立即退出了。 为了解决这个问题,您可以在调用 shell 脚本的代码中,使用 `ChannelExec.setPty(true)` 方法启用伪终端模式,并使用 `ChannelExec.setCommand(command + ";echo finished")` 方法在 shell 脚本执行完毕后输出一个 "finished" 的标识符。然后您可以使用 `ChannelExec.getInputStream()` 方法获取 shell 脚本的输出流,并等待输出流中包含 "finished" 标识符,表示 shell 脚本已经执行完毕,然后再关闭连接。 以下是一个示例代码: ``` JSch jsch = new JSch(); Session session = jsch.getSession(username, host, port); session.setPassword(password); session.setConfig("StrictHostKeyChecking", "no"); session.connect(); ChannelExec channelExec = (ChannelExec) session.openChannel("exec"); channelExec.setPty(true); channelExec.setCommand(command + ";echo finished"); channelExec.setInputStream(null); channelExec.setErrStream(System.err); InputStream inputStream = channelExec.getInputStream(); channelExec.connect(); byte[] tmp = new byte[1024]; while (true) { while (inputStream.available() > 0) { int i = inputStream.read(tmp, 0, 1024); if (i < 0) break; System.out.print(new String(tmp, 0, i)); } if (channelExec.isClosed()) { if (inputStream.available() > 0) continue; System.out.println("exit-status: " + channelExec.getExitStatus()); break; } try { Thread.sleep(1000); } catch (Exception ee) {} } channelExec.disconnect(); session.disconnect(); ``` 希望这个解答能够帮到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值