使用JSch远程执行nohup后台脚本:是否必须读取InputStream?
问题解答
1. 是否必须读取channel.getInputStream()的输入流?
不是必须,但建议处理输入流,否则可能出现通道阻塞、无法正常断开连接的情况。
你的命令已经通过> /home/user1/output.txt 2>&1 &把脚本的标准输出、错误输出全部重定向到文件,并且让脚本在后台运行,理论上通道的输入流不会有大量数据。但SSH服务器可能会返回少量通道相关的输出(比如nohup的初始化提示、通道关闭信号),如果不读取这些数据,JSch的通道可能会因为缓冲区被占满而卡住,导致channel.disconnect()或session.disconnect()无法立即执行,甚至脚本进程被意外终止。
如果完全不想处理输入流,可以直接将输入流忽略,同时可以把标准输出和错误输出都重定向到/dev/null(不需要保存日志的话),命令改成:
nohup script.sh > /dev/null 2>&1 &
2. 若需要读取输入流,如何快速收回控制权?
如果要确保通道正常关闭又不想等待脚本执行完成,可以用以下两种方式快速处理输入流:
方式一:用线程异步读取输入流
启动独立线程读取输入流剩余数据,主线程无需等待,直接执行断开操作:
String command = "nohup script.sh > /home/user1/output.txt 2>&1 &"; session.connect(); ChannelExec channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(command); channel.setInputStream(null); // 把错误输出也重定向到文件,避免占用通道缓冲区 ((ChannelExec) channel).setErrStream(new FileOutputStream("/home/user1/error.txt")); InputStream in = channel.getInputStream(); channel.connect(); // 启动线程异步读取输入流,不阻塞主线程 new Thread(() -> { byte[] buffer = new byte[1024]; try { while (in.read(buffer) != -1) { // 直接丢弃数据,无需处理 } } catch (IOException e) { // 通道关闭时会触发异常,直接忽略 } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); // 主线程直接断开通道和会话,无需等待脚本完成 Thread.sleep(100); // 可选:短暂等待确保线程启动,避免通道未建立就断开 channel.disconnect(); session.disconnect();
方式二:一次性读取缓冲区所有数据后立即断开
如果输入流中只有少量数据,可一次性读取当前缓冲区的全部可用数据,然后立即断开:
String command = "nohup script.sh > /home/user1/output.txt 2>&1 &"; session.connect(); ChannelExec channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(command); channel.setInputStream(null); ((ChannelExec) channel).setErrStream(System.err); InputStream in = channel.getInputStream(); channel.connect(); // 读取当前缓冲区所有可用数据,不等待后续输出 byte[] buffer = new byte[in.available()]; in.read(buffer); // 直接断开连接 channel.disconnect(); session.disconnect();
注意:in.available()仅能获取当前缓冲区的可用数据量,无法保证读取到所有数据,但对于后台执行的nohup命令来说,此时通道输入流通常只有少量初始化信息,这种方式足够快速收回控制权。
内容的提问来源于stack exchange,提问作者itsraja
相关产品推荐
相关产品推荐

