You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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 like sudo and sqlplus require a pseudo-terminal to work correctly.
  • Prompt Handling: The waitForPrompt method 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 PromiscuousVerifier in production—instead, use proper host key verification to prevent man-in-the-middle attacks.
  • Timeouts: Adjust the timeouts in waitForPrompt based on how long each command takes (especially impdp, 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 sysdba without 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.log for sudo issues, Oracle alert logs for SQL errors).

内容的提问来源于stack exchange,提问作者user9558800

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:54:06