[原]使用Jsch执行Shell脚本

首发CSDN http://blog.csdn.net/basecn/archive/2010/12/16/6080741.aspx

作者:BaseCN Email:basecn@163.com

-----------------------------------------------

Jsch是JAVA的SSH客户端,使用的目的是执行远程服务器上的命令。

 

关于Session的使用,创建连接后这个session是一直可用的,所以不需要关闭。由Session中open的Channel在使用后应该关闭。

 

测试了exec的方式,具体参考jsch自带example中的Exec.java。

有两个问题:

1、无法执行多条命令,每次ChannelExec在connect前要先setCommand,最后一次的设置生效。

2、由于第一个原因的限制,如果执行的命令需要环境变量(如JAVA_HOME),就没有办法了。这种方式执行基本的ls,ps之类的命令没有问题,需要复杂的环境变量时有点力不从心。

 

要是哪位知道exec如何解决上面现两个问题,请分享一下!

-----------------------------------------------

虽然exec可以得到命令的执行结果,但无法满足应用,无奈之下放弃exec转而使用ChannelShell。

在使用ChannelShell的时候需要特别关注jsch的输入和输出流的设置。

输出

为了得到脚本的运行结果,设置jsch的outputStream为FileOutputStream,把shell的输出结果保存到本地文件。虽然最简单的方式是设置System.out为jsch的OutputStream,在控制台看到结果,只是无法保存下来。

FileOutputStream fileOut = new FileOutputStream( outputFileName ); channelShell.setOutputStream( fileOut ); 

输入

短时间运行的程序,输入可以直接设置为System.in,而长期运行的程序不能使用人工方式输入,必须由程序自动生成命令来执行。所以使用PipeStream来实现字符串输入命令:

PipedInputStream pipeIn = new PipedInputStream(); PipedOutputStream pipeOut = new PipedOutputStream( pipeIn ); channelShell.setInputStream( pipeIn );  

调用pipeOut.write( cmd.getBytes() );把生成的命令输出给ssh。

运行

jsch是以多线程方式运行的,所以代码在connect后如果不disconnect Channel和Session,以及相关的Stream,程序会一直等待,直到关闭,目前还没有找到判断关闭或主动关闭的方法,相信应该有这方面的机制。

 

要注意一个问题,相关的Stream和Channel是一定要关闭的,那么应该在什么时候来关。执行connect后,jsch接收客户端结果需要一定的时间(以秒计),如果马上关闭session就会发现什么都没接收到或内容不全。

 

可以采取两个办法来解决这个问题,一个开源一个节流

1、在connect增加一个等待延迟,等待1~2秒,这个是开源;

2、减小server端脚本的执行时间,这个是节流。给命令加上"nohup XXXX > output &",以后台方式运行,并把运行结果输出到服务器端的本地目录下。这样脚本的执行时间可以是最小。

-----------------------------------------------

最后还有一点注意,使用shell时,看到有的朋友说执行后没有结果。解决的办法是在命令后加上"/n"字符,server端就认为是一条完整命令了。很奇怪的特性!

-----------------------------------------------

附上类代码

package jsch; import static java.lang.String.format; import java.io.Closeable; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelShell; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import com.jcraft.jsch.UserInfo; import com.nsm.hermes.wand.Wand; public class SshExecuter implements Closeable{ static long interval = 1000L; static int timeout = 3000; private SshInfo sshInfo = null; private JSch jsch = null; private Session session = null; private SshExecuter( SshInfo info ) throws Exception{ sshInfo = info; jsch = new JSch(); jsch.addIdentity( sshInfo.getKey() ); session = jsch.getSession( sshInfo.getUser(), sshInfo.getHost(), sshInfo.getPort() ); UserInfo ui = new SshUserInfo( sshInfo.getPassPhrase() ); session.setUserInfo( ui ); session.connect(); } public long shell( String cmd, String outputFileName ) throws Exception{ long start = System.currentTimeMillis(); ChannelShell channelShell = (ChannelShell)session.openChannel( "shell" ); PipedInputStream pipeIn = new PipedInputStream(); PipedOutputStream pipeOut = new PipedOutputStream( pipeIn ); FileOutputStream fileOut = new FileOutputStream( outputFileName ); channelShell.setInputStream( pipeIn ); channelShell.setOutputStream( fileOut ); channelShell.connect( timeout ); pipeOut.write( cmd.getBytes() ); Thread.sleep( interval ); pipeOut.close(); pipeIn.close(); fileOut.close(); channelShell.disconnect(); return System.currentTimeMillis() - start; } public int exec( String cmd ) throws Exception{ ChannelExec channelExec = (ChannelExec)session.openChannel( "exec" ); channelExec.setCommand( cmd ); channelExec.setInputStream( null ); channelExec.setErrStream( System.err ); InputStream in = channelExec.getInputStream(); channelExec.connect(); int res = -1; 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 ( channelExec.isClosed() ) { res = channelExec.getExitStatus(); System.out.println( format( "Exit-status: %d", res ) ); break; } Wand.waitA( 100 ); } System.out.println( buf.toString() ); channelExec.disconnect(); return res; } public static SshExecuter newInstance() throws Exception{ String host = "localhost"; Integer port = 22; String user = "hadoop"; String key = "./id_dsa"; String passPhrase = ""; SshInfo i = new SshInfo( host, port, user, key, passPhrase ); return new SshExecuter( i ); } public Session getSession(){ return session; } public void close() throws IOException{ getSession().disconnect(); } } class SshInfo{ String host = null; Integer port = 22; String user = null; String key = null; String passPhrase = null; public SshInfo( String host, Integer port, String user, String key, String passPhrase ){ super(); this.host = host; this.port = port; this.user = user; this.key = key; this.passPhrase = passPhrase; } public String getHost(){ return host; } public Integer getPort(){ return port; } public String getUser(){ return user; } public String getKey(){ return key; } public String getPassPhrase(){ return passPhrase; } } class SshUserInfo implements UserInfo{ private String passphrase = null; public SshUserInfo( String passphrase ){ super(); this.passphrase = passphrase; } public String getPassphrase(){ return passphrase; } public String getPassword(){ return null; } public boolean promptPassphrase( String pass ){ return true; } public boolean promptPassword( String pass ){ return true; } public boolean promptYesNo( String arg0 ){ return true; } public void showMessage( String m ){ System.out.println( m ); } }

 

 

 

作者:basecn 发表于2010-12-16 19:04:00 原文链接
阅读:770 评论:1 查看评论

转载于:https://www.cnblogs.com/basecn/archive/2010/12/16/3264310.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
系统根据B/S,即所谓的电脑浏览器/网络服务器方式,运用Java技术性,挑选MySQL作为后台系统。系统主要包含对客服聊天管理、字典表管理、公告信息管理、金融工具管理、金融工具收藏管理、金融工具银行卡管理、借款管理、理财产品管理、理财产品收藏管理、理财产品银行卡管理、理财银行卡信息管理、银行卡管理、存款管理、银行卡记录管理、取款管理、转账管理、用户管理、员工管理等功能模块。 文中重点介绍了银行管理的专业技术发展背景和发展状况,随后遵照软件传统式研发流程,最先挑选适用思维和语言软件开发平台,依据需求分析报告模块和设计数据库结构,再根据系统功能模块的设计制作系统功能模块图、流程表和E-R图。随后设计架构以及编写代码,并实现系统能模块。最终基本完成系统检测和功能测试。结果显示,该系统能够实现所需要的作用,工作状态没有明显缺陷。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。进入银行卡列表,管理员可以进行查看列表、模糊搜索以及相关维护等操作。用户进入系统可以查看公告和模糊搜索公告信息、也可以进行公告维护操作。理财产品管理页面,管理员可以进行查看列表、模糊搜索以及相关维护等操作。产品类型管理页面,此页面提供给管理员的功能有:新增产品类型,修改产品类型,删除产品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值