通过 Java JSch 库在远程机器上执行本地脚本
Execute a local script on a remote machine through Java JSch library
我正在监控一组远程服务器上的错误日志。为此,我正在监视在一段时间内修改的日志。
我正在使用 Jsch Java library
创建一个 SSH connection
并执行命令。正如我所搜索的,多个命令可以通过 ;
分隔不同的命令来远程机器
为此,我有一个文本文件,其中包含我正在建立连接的远程主机的列表。我意识到我可以获得通过以下命令修改的所有文件的列表
find . -mmin -60 -type f -exec ls {} +
不,我可以遍历文件和 grep for the Error
。为此,我编写了以下脚本
logTestScript.sh
#!/bin/bash
cd /log
searchString='<Error ErrorCode="java.sql.SQLException"'
files=`find . -mmin -60 -type f -exec ls {} +`
pwd
hostname
echo ${files}
for file in ${files[@]}
do
if grep -Fq "$searchString" $file
then
echo "String found in $file"
fi
done
现在这个脚本存在于我运行正在使用java程序的当前包中,我希望运行每个远程主机上的这个脚本。
下面是我当前使用 ChannelExec
的代码
private void getSSHConnection() throws IOException, JSchException {
username = props.getProperty("host_username");
password = props.getProperty("host_password");
log_traceback_interval = props.getProperty("fetch_logs_interval_minutes");
errorString = props.getProperty("error_message_log");
System.out.println(username + " " + password + " " + errorString);
// Get the hostnames resource file
String hostnameResourcePath = envObj.getAgentHostnamesConfig(TargetEnvironment, ManagementSystem);
InputStream hostInpStream = this.getClass().getResourceAsStream(hostnameResourcePath);
BufferedReader hostnameReader = new BufferedReader(new InputStreamReader(hostInpStream));
String host = null;
while((host = hostnameReader.readLine()) != null) {
System.out.println(host);
// get a JSch connection object
JSch jschObj = new JSch();
Session session = jschObj.getSession(username, host);
// Disable StrictHost key checking
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
//Execute channel instance
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
InputStream in = channelExec.getInputStream();
//Bash script command with arguments
StringBuilder sb = new StringBuilder();
String command = sb.append("cd /log").append(";")
.append("echo `find . -mmin -60 -type f -exec ls {} +`").append(";")
.toString();
System.out.println(command);
//Run the script on host
channelExec.setCommand(command); //I want to run the script here instead of each command as it uses for loop
channelExec.setInputStream(null);
channelExec.setErrStream(System.err);
InputStream monitorLogs = channelExec.getInputStream();
channelExec.connect();
//Read the logs
BufferedReader logReader = new BufferedReader(new InputStreamReader(monitorLogs));
String logLine;
while((logLine = logReader.readLine()) != null) {
System.out.println(logLine);
}
//Close the connections
channelExec.disconnect();
session.disconnect();
}
}
我能想到的一个解决方案是将脚本通过 SCP 发送到远程主机,然后在那里执行。
但是有没有一些简单的解决方案,即使不编写脚本并且只在远程服务器上执行命令或执行脚本,我也可以获得相同的结果。
感谢帮助
您不能在服务器上执行本地脚本。
你有两个选择(你显然知道):
- 上传脚本并执行(如果需要,之后删除)。
执行脚本的内容。如您所知,只需将所有行与 ;
连接起来。
不过要小心 for
和 if
。 do
和 then
之后不应该有 ;
。
cd /log ; searchString='<Error ErrorCode="java.sql.SQLException"' ; files=`find . -mmin -60 -type f -exec ls {} +` ; echo `pwd` ; echo `hostname` ; echo ${files} ; for file in ${files[@]} ; do if grep -Fq "$searchString" $file ; then echo "String found in $file" ; fi ; done
与前面的方法类似,您可以执行 bash -s
并将脚本的内容(命令)写入其输入。
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
channelExec.setCommand("bash -s");
channelExec.connect();
OutputStream out = channel.getOutputStream();
FileInputStream fis = new FileInputStream("testScript.sh");
byte[] buf = new byte[1024];
while (true)
{
int len = fis.read(buf, 0, buf.length);
if (len <= 0) break;
out.write(buf, 0, len);
}
以上基本上是从看似无关的SCP upload example复制而来的-该示例实际上将本地文件提供给远程scp
进程-所以它实际上非常相关。
Ntb,"echo `pwd`" 和 "echo `hostname`" 没有意义。直接使用"pwd"和"hostname"。
为了在远程服务器上执行脚本 script.sh
,您可以使用以下代码 -
#!/usr/bin/expect
export PASSD="User@123"
expect -c 'spawn sftp user@xxxxxx.com;
expect "*Password: ";
send "$env(PASSD)\r";
expect "ssh>";
send "cd /home/user \r";
expect "ssh>";
send "sh -x script.sh \r";
expect "ssh>";
send "exit \r"'
您可以将以上代码放在脚本中,然后在您的 if 循环的成功条件之后添加。
我正在监控一组远程服务器上的错误日志。为此,我正在监视在一段时间内修改的日志。
我正在使用 Jsch Java library
创建一个 SSH connection
并执行命令。正如我所搜索的,多个命令可以通过 ;
为此,我有一个文本文件,其中包含我正在建立连接的远程主机的列表。我意识到我可以获得通过以下命令修改的所有文件的列表
find . -mmin -60 -type f -exec ls {} +
不,我可以遍历文件和 grep for the Error
。为此,我编写了以下脚本
logTestScript.sh
#!/bin/bash
cd /log
searchString='<Error ErrorCode="java.sql.SQLException"'
files=`find . -mmin -60 -type f -exec ls {} +`
pwd
hostname
echo ${files}
for file in ${files[@]}
do
if grep -Fq "$searchString" $file
then
echo "String found in $file"
fi
done
现在这个脚本存在于我运行正在使用java程序的当前包中,我希望运行每个远程主机上的这个脚本。
下面是我当前使用 ChannelExec
private void getSSHConnection() throws IOException, JSchException {
username = props.getProperty("host_username");
password = props.getProperty("host_password");
log_traceback_interval = props.getProperty("fetch_logs_interval_minutes");
errorString = props.getProperty("error_message_log");
System.out.println(username + " " + password + " " + errorString);
// Get the hostnames resource file
String hostnameResourcePath = envObj.getAgentHostnamesConfig(TargetEnvironment, ManagementSystem);
InputStream hostInpStream = this.getClass().getResourceAsStream(hostnameResourcePath);
BufferedReader hostnameReader = new BufferedReader(new InputStreamReader(hostInpStream));
String host = null;
while((host = hostnameReader.readLine()) != null) {
System.out.println(host);
// get a JSch connection object
JSch jschObj = new JSch();
Session session = jschObj.getSession(username, host);
// Disable StrictHost key checking
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
//Execute channel instance
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
InputStream in = channelExec.getInputStream();
//Bash script command with arguments
StringBuilder sb = new StringBuilder();
String command = sb.append("cd /log").append(";")
.append("echo `find . -mmin -60 -type f -exec ls {} +`").append(";")
.toString();
System.out.println(command);
//Run the script on host
channelExec.setCommand(command); //I want to run the script here instead of each command as it uses for loop
channelExec.setInputStream(null);
channelExec.setErrStream(System.err);
InputStream monitorLogs = channelExec.getInputStream();
channelExec.connect();
//Read the logs
BufferedReader logReader = new BufferedReader(new InputStreamReader(monitorLogs));
String logLine;
while((logLine = logReader.readLine()) != null) {
System.out.println(logLine);
}
//Close the connections
channelExec.disconnect();
session.disconnect();
}
}
我能想到的一个解决方案是将脚本通过 SCP 发送到远程主机,然后在那里执行。
但是有没有一些简单的解决方案,即使不编写脚本并且只在远程服务器上执行命令或执行脚本,我也可以获得相同的结果。
感谢帮助
您不能在服务器上执行本地脚本。
你有两个选择(你显然知道):
- 上传脚本并执行(如果需要,之后删除)。
执行脚本的内容。如您所知,只需将所有行与
;
连接起来。不过要小心
for
和if
。do
和then
之后不应该有;
。cd /log ; searchString='<Error ErrorCode="java.sql.SQLException"' ; files=`find . -mmin -60 -type f -exec ls {} +` ; echo `pwd` ; echo `hostname` ; echo ${files} ; for file in ${files[@]} ; do if grep -Fq "$searchString" $file ; then echo "String found in $file" ; fi ; done
与前面的方法类似,您可以执行
bash -s
并将脚本的内容(命令)写入其输入。ChannelExec channelExec = (ChannelExec)session.openChannel("exec"); channelExec.setCommand("bash -s"); channelExec.connect(); OutputStream out = channel.getOutputStream(); FileInputStream fis = new FileInputStream("testScript.sh"); byte[] buf = new byte[1024]; while (true) { int len = fis.read(buf, 0, buf.length); if (len <= 0) break; out.write(buf, 0, len); }
以上基本上是从看似无关的SCP upload example复制而来的-该示例实际上将本地文件提供给远程
scp
进程-所以它实际上非常相关。
Ntb,"echo `pwd`" 和 "echo `hostname`" 没有意义。直接使用"pwd"和"hostname"。
为了在远程服务器上执行脚本 script.sh
,您可以使用以下代码 -
#!/usr/bin/expect
export PASSD="User@123"
expect -c 'spawn sftp user@xxxxxx.com;
expect "*Password: ";
send "$env(PASSD)\r";
expect "ssh>";
send "cd /home/user \r";
expect "ssh>";
send "sh -x script.sh \r";
expect "ssh>";
send "exit \r"'
您可以将以上代码放在脚本中,然后在您的 if 循环的成功条件之后添加。