使用带有JSch的SCP时如何逃避双引号?

时间:2017-10-09 15:34:16

标签: java quotes scp jsch java.nio.file

在Windows系统上安装了SSH,并与远程主机(Linux)交换密钥。我想在Windows机器上运行一个JAR到SCP机器的SCP文件。 使用

在命令行上执行此操作
"C:/Program Files (X86)/ICW/bin/SCP.exe" -i .ssh/id_rsa <filename> theUser@xxx.xxx.xx.xx:/target/path/<filename>

效果很好(使用双引号)。

但是当我使用 JSch 从JAR中运行SCP时,我得到了一个sun.nio.file.InvalidPathException:非法的char&lt;&#34;&gt;在索引......

目的是我必须从FTP主机以编程方式收集一堆文件(我已经使这部分工作了)。必须将这些文件转发到已提到的远程主机。 FTP主机和远程主机无法相互直接通信。因此,Windows机器充当一种代理。 JAR从FTP服务器获取文件(目前将它们保存在地图中),我想使用JSch SCP直接将它们放入远程Linux主机上的特定文件夹中。

我该如何解决这个问题?如何解决这个双引号问题

    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();
        }
    }

其中 vaFiles 是Map&lt; String,byte []&gt;和 scp.command 来自属性文件,是

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

(我试图用单引号括起来,双引号,没有引号,没有\ u0020,......)

使用 MessageFormat 填充

{0} =&#39; \&#34; C:/ Program \ u0020Files \ u0020(x86)/ICW/bin/scp.exe \&#34;&#39;

{1} =文件名

{2} = scp用户名

{3} = scp hist IP地址

{4} =远程主机上的目标路径

{5} =文件名(参见{1})

SFTP目前没有选项,只有SCP安装在Windows机器和远程Linux主机上。 如果我在这方面有完全的误解,我会很感激任何技术转让,以了解如何以正确的方式做到这一点。 : - )

2 个答案:

答案 0 :(得分:1)

您显然是在尝试从本地Windows 计算机启动SCP文件传输到远程Linux 计算机。

但是你的代码所做的是,它是ssh到远程Linux 机器并尝试在那里运行Windows风格的命令C:\Program Files (x86)\ICW\bin\scp.exe。无论你使用什么样的报价,这都行不通。

  1. 不要使用SCP,它是一种古老的协议。使用SFTP。所有Linux机器都支持SFTP。 JSch也对SFTP提供原生支持。您不需要任何本地OpenSSH安装。

  2. 即使您决定坚持使用SCP,将JSch SSH / SFTP库与本地独立SCP客户端结合起来也毫无意义。

答案 1 :(得分:1)

好的,马丁,谢谢你指导我正确的方向。可能我会检查并尝试使用SFTP实现它。 暂时你帮助我使用SCP实现至少一个工作版本(即使它是一个古老的协议):

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();
    }
}