基于sshj实现远程服务器连接及多步骤命令执行方案咨询
Using sshj to Execute Interactive Remote Commands (Oracle, SQLPlus, Impdp)
Hey there! Let's walk through the cleanest way to automate your sequence of commands using sshj. The key here is handling interactive prompts (like sudo password, SQLPlus login) by using a pseudo-terminal (PTY) and managing input/output streams to respond to prompts as they appear.
Step 1: Add sshj Dependency
First, make sure you have sshj in your project. If using Maven, add this to your pom.xml:
<dependency> <groupId>com.hierynomus</groupId> <artifactId>sshj</artifactId> <version>0.37.0</version> <!-- Use the latest stable version --> </dependency>
Step 2: Complete Implementation Code
Here's a full, commented implementation that handles all your steps. I've included error handling and resource management:
import com.hierynomus.sshj.SSHClient; import com.hierynomus.sshj.connection.channel.direct.Session; import com.hierynomus.sshj.connection.channel.direct.Session.Shell; import com.hierynomus.sshj.transport.verification.PromiscuousVerifier; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.concurrent.TimeUnit; public class RemoteOracleExecutor { private static final String REMOTE_HOST = "your-server-ip"; private static final String USERNAME = "your-ssh-username"; private static final String SSH_PASSWORD = "your-ssh-password"; private static final String SUDO_PASSWORD = SSH_PASSWORD; // Usually same as SSH password, adjust if different private static final String ORACLE_SYS_PASSWORD = "your-oracle-sys-password"; // Skip if using OS auth public static void main(String[] args) { SSHClient sshClient = new SSHClient(); Shell shell = null; BufferedReader reader = null; Writer writer = null; try { // Disable host key verification (not recommended for production!) sshClient.addHostKeyVerifier(new PromiscuousVerifier()); sshClient.connect(REMOTE_HOST); sshClient.authPassword(USERNAME, SSH_PASSWORD); // Start a PTY session to handle interactive commands Session session = sshClient.startSession(); session.allocateDefaultPTY(); shell = session.startShell(); // Get input/output streams to interact with the shell reader = new BufferedReader(new InputStreamReader(shell.getInputStream())); writer = new OutputStreamWriter(shell.getOutputStream()); // Wait for initial shell prompt (adjust timeout as needed) waitForPrompt(reader, "[$#>]", 10, TimeUnit.SECONDS); // Step 2: Execute sudo su - oracle sendCommand(writer, "sudo su - oracle"); // Wait for sudo password prompt waitForPrompt(reader, "[sudo] password for ", 5, TimeUnit.SECONDS); sendCommand(writer, SUDO_PASSWORD); // Wait for oracle user prompt (usually ends with $ or >) waitForPrompt(reader, "[$>]", 10, TimeUnit.SECONDS); // Step 4: Run sqlplus /nolog sendCommand(writer, "sqlplus /nolog"); // Wait for SQLPlus prompt waitForPrompt(reader, "SQL>", 5, TimeUnit.SECONDS); // Step 5: Connect as sysdba // If using OS authentication (no password needed): sendCommand(writer, "connect / as sysdba"); // If you need to provide a password: // sendCommand(writer, "connect sys/" + ORACLE_SYS_PASSWORD + " as sysdba"); // Wait for connected prompt waitForPrompt(reader, "Connected.", 5, TimeUnit.SECONDS); // Step 6: Execute your SQL commands sendCommand(writer, "ALTER SYSTEM CHECKPOINT;"); waitForPrompt(reader, "SQL>", 5, TimeUnit.SECONDS); sendCommand(writer, "SELECT SYSDATE FROM DUAL;"); waitForPrompt(reader, "SQL>", 5, TimeUnit.SECONDS); // Exit SQLPlus sendCommand(writer, "EXIT;"); waitForPrompt(reader, "[$>]", 10, TimeUnit.SECONDS); // Step 7: Run impdp command sendCommand(writer, "impdp your_username/your_password@your_schema dumpfile=your_dump.dmp logfile=impdp.log"); // Wait for impdp to finish (adjust timeout based on your dump size) waitForPrompt(reader, "[$>]", 30, TimeUnit.MINUTES); System.out.println("All commands executed successfully!"); } catch (IOException | InterruptedException e) { e.printStackTrace(); } finally { // Clean up resources try { if (writer != null) writer.close(); if (reader != null) reader.close(); if (shell != null) shell.close(); if (sshClient != null) sshClient.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } /** * Sends a command to the remote shell and flushes the writer. */ private static void sendCommand(Writer writer, String command) throws IOException { writer.write(command + "\n"); writer.flush(); } /** * Waits for a specific prompt pattern in the remote shell output. * @param reader The buffered reader for shell input * @param promptPattern Regex pattern to match the prompt * @param timeout Maximum time to wait * @param timeUnit Unit for the timeout */ private static void waitForPrompt(BufferedReader reader, String promptPattern, long timeout, TimeUnit timeUnit) throws IOException, InterruptedException { long endTime = System.currentTimeMillis() + timeUnit.toMillis(timeout); StringBuilder output = new StringBuilder(); String line; while (System.currentTimeMillis() < endTime) { if (reader.ready()) { line = reader.readLine(); if (line == null) break; output.append(line).append("\n"); // Check if the line matches the prompt pattern if (line.matches(".*" + promptPattern + ".*")) { System.out.println("Received prompt: " + line); return; } } TimeUnit.MILLISECONDS.sleep(100); } throw new InterruptedException("Timeout waiting for prompt. Output received so far:\n" + output); } }
Key Notes & Best Practices
- PTY Session: We use
allocateDefaultPTY()because interactive commands likesudoandsqlplusrequire a pseudo-terminal to work correctly. - Prompt Handling: The
waitForPromptmethod listens for specific prompt patterns to know when to send the next command. Adjust the regex patterns if your server's prompts are different (e.g., some Oracle shells end with%). - Security:
- Never hardcode passwords in production! Use environment variables, a secure vault (like HashiCorp Vault), or encrypted configuration files.
- Disable
PromiscuousVerifierin production—instead, use proper host key verification to prevent man-in-the-middle attacks.
- Timeouts: Adjust the timeouts in
waitForPromptbased on how long each command takes (especiallyimpdp, which can take minutes/hours depending on the dump size). - OS Authentication: If your server is configured for OS authentication for Oracle sysdba, you can use
connect / as sysdbawithout a password, which simplifies the code.
Troubleshooting Tips
- If prompts aren't being detected, print the full output from the reader to see what's actually being sent by the server, then adjust the regex pattern.
- If commands fail, check the remote server's logs (e.g.,
/var/log/auth.logfor sudo issues, Oracle alert logs for SQL errors).
内容的提问来源于stack exchange,提问作者user9558800
相关产品推荐
相关产品推荐

