简体   繁体   中英

How can I escape doublequotes when using SCP with JSch?

On a Windows system is SSH installed and keys are exchanged with a remote host (Linux). I want to run a JAR on the windows machine to SCP files to the Linux machine. Doing this on the command line with

"C:/Program Files (X86)/ICW/bin/SCP.exe" -i .ssh/id_rsa <filename> theUser@xxx.xxx.xx.xx:/target/path/<filename>

it works well (using the double quotes).

But when I run the SCP from within the JAR using JSch I get a sun.nio.file.InvalidPathException: Illegal char <"> at index...

The intention is that I have to gather a bunch of files programmatically from an FTP host (I already got this part working). These files must be forwarded to the already mentioned remote host. The FTP host and the remote host cannot communicate direcly with each other. Thus, the Windows machine acts as a kind of broker. The JAR gets the files from the FTP server (currently keeping them in a map) and I want to use JSch SCP to directly put them into a particular folder on the remote Linux host.

How can I solve this problem? How to solve this double quote issue ?

    private void storeFiles() throws IOException {
        final JSch jsch = new JSch();
        final FileSystem fs = FileSystems.getDefault();
        final Path p = fs.getPath( getProperty("scp.key.file.private"));
        logger.info("Reading private key from " + getProperty("scp.key.file.private"));

        final Session session;
        try {
            session = jsch.getSession(getProperty("scp.user.name"), getProperty("scp.host.ip"),
                    Integer.parseInt(getProperty("scp.port")));
            jsch.addIdentity(p.toFile().getPath());
            final Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();
            logger.info("Connected to " + getProperty("scp.host.ip") + "...");

            vaFiles.forEach((k, v) ->{
                // get I/O streams for remote scp
                try {
                    final MessageFormat mf = new MessageFormat(getProperty("scp.command"));
                    final Object[] commandArgs = new Object[]{getProperty("scp.key.file.private"),
                            k, getProperty("scp.user.name"),
                            getProperty("scp.host.ip"),
                            getProperty("scp.target.path"), k};
                    final String command = mf.format(commandArgs);
                    logger.info(command);
                    final Channel channel;
                    try {
                        channel = session.openChannel("exec");
                        channel.connect();
                        ((ChannelExec)channel).setCommand(command);
//                        logger.info("Writing " + Arrays.toString(v) + " to SCP channel...");
                        final OutputStream out = channel.getOutputStream();
                        out.write(command.getBytes());
                        out.flush();
                        out.write(v);
                        out.close();
                        channel.disconnect();
                    } catch (JSchException e) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }); //end forEach
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();
        }
    }

Whereby vaFiles is Map<String, byte[]> and scp.command comes from a properties file and is

scp.command = '\"C\:/Program\u0020Files\u0020(x86)/ICW/bin/scp.exe\"' -i {0} {1} {2}@{3}\:{4}/{5} 

(I tried to wrap the command string in single quotes, double quotes, without quotes, without \ , ...)

being filled up using MessageFormat with

{0} = '\\"C:/Program\ Files\ (x86)/ICW/bin/scp.exe\\"'

{1} = the filename

{2} = scp username

{3} = scp hist IP address

{4} = target path on remote host

{5} = the filename (see {1})

SFTP is currently no option, only SCP is installed on the Windows machine and the remote Linux host. If I have complete misunderstanding in doing this I would appreciate any know-how transfer to learn how to do it the proper way. :-)

You are obviously trying to initiate an SCP file transfer from a local Windows machine to a remote Linux machine.

But what you code does, is that it ssh to the remote Linux machine and tries to run Windows-style command C:\\Program Files (x86)\\ICW\\bin\\scp.exe there. That cannot work, no matter, what kind of quotation you will use.

  1. Do not use SCP, it's an ancient protocol. Use SFTP. All Linux machines support SFTP. JSch has a native support for SFTP too. You won't need any local OpenSSH installation.

  2. Even if you decide to stick with SCP, it makes no sense to combine JSch SSH/SFTP library with a local standalone SCP client.

    • Either use a native Java SCP implementation:
      http://www.jcraft.com/jsch/examples/ScpTo.java.html
      (and you won't need the local OpenSSH installation)

    • Or run scp.exe locally (and you won't need JSch SSH library) - though I do not recommend this option at all.

Okay, Martin, thank you for guiding me in the right direction. Probably I will check and try to implement it using SFTP. For the time being you helped my to implement at least a working version using SCP (even though it's an ancient protocol):

private void storeFilesSCP() throws IOException {
    final JSch jsch = new JSch();
    final FileSystem fs = FileSystems.getDefault();
    final Path p = fs.getPath( getProperty("scp.key.file.private"));
    logger.info("Reading private key from " + getProperty("scp.key.file.private"));

    final Session session;
    try {
        session = jsch.getSession(getProperty("scp.user.name"), getProperty("scp.host.ip"),
                Integer.parseInt(getProperty("scp.port")));
        jsch.addIdentity(p.toFile().getPath());
        final Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        final UserInfo userInfo = new UserInfo();
        session.setUserInfo(userInfo);
        session.connect();
        logger.info("Connected to " + getProperty("scp.host.ip") + "...");

        vaFiles.forEach((k, v) ->{
            // get I/O streams for remote scp
            try {
                final Channel channel;
                String command = "scp -t " + getProperty("scp.target.path") + "/" + k + " ";
                System.out.println(command);
                try {
                    channel = session.openChannel("exec");
                    ((ChannelExec)channel).setCommand(command);
                    channel.connect();
                    command="C0644 " + v.length + " " + k + "\n";
                    System.out.println(command);
                    final OutputStream out = channel.getOutputStream();
                    out.write(command.getBytes());
                    out.flush();
                    out.write(v);
                    out.flush();
                    out.close();
                    channel.disconnect();
                } catch (JSchException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }); //end forEach
        session.disconnect();
    } catch (JSchException e) {
        e.printStackTrace();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM