将 SCP 与 JSch 一起使用时如何转义双引号?
How can I escape doublequotes when using SCP with JSch?
在 Windows 系统上安装了 SSH,并与远程主机 (Linux) 交换密钥。我想 运行 windows 机器上的一个 JAR 到 Linux 机器上的 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: Illegal char <"> at index...
目的是我必须以编程方式从 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 并且 scp.command 来自属性文件并且是
scp.command = '\"C\:/Program\u0020Files\u0020(x86)/ICW/bin/scp.exe\"' -i {0} {1} {2}@{3}\:{4}/{5}
(我试过把命令字符串用单引号、双引号、不带引号、不带\u0020、...)
正在使用 MessageFormat 填充
{0} = '\"C:/Program\u0020Files\u0020(x86)/ICW/bin/scp.exe\"'
{1} = 文件名
{2} = scp 用户名
{3} = scp hist IP 地址
{4} = 远程主机上的目标路径
{5} = 文件名(参见{1})
SFTP目前没有选项,只有SCP安装在Windows机器和远程Linux主机上。
如果我在这样做时完全误解了,我将不胜感激任何知识转移以学习如何以正确的方式做到这一点。 :-)
您显然是在尝试启动从 本地 Windows 机器到 远程 Linux[=36] 的 SCP 文件传输=]机.
但是您的代码所做的是,它通过 ssh 连接到 远程 Linux 机器并尝试使用 运行 Windows 样式的命令C:\Program Files (x86)\ICW\bin\scp.exe
那里。那不行,不管你用什么报价。
不要使用 SCP,这是一个古老的协议。使用 SFTP。所有 Linux 台机器都支持 SFTP。 JSch 也有对 SFTP 的本地支持。您不需要任何本地 OpenSSH 安装。
即使您决定坚持使用 SCP,将 JSch SSH/SFTP 库与本地独立 SCP 客户端结合使用也没有任何意义。
要么使用本机 Java SCP 实现:
http://www.jcraft.com/jsch/examples/ScpTo.java.html
(并且您不需要本地 OpenSSH 安装)
或 运行 scp.exe
在本地(并且您不需要 JSch SSH 库)- 尽管我根本不推荐此选项。
好的,Martin,谢谢你指引我正确的方向。可能我会检查并尝试使用 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();
}
}
在 Windows 系统上安装了 SSH,并与远程主机 (Linux) 交换密钥。我想 运行 windows 机器上的一个 JAR 到 Linux 机器上的 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: Illegal char <"> at index...
目的是我必须以编程方式从 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
scp.command = '\"C\:/Program\u0020Files\u0020(x86)/ICW/bin/scp.exe\"' -i {0} {1} {2}@{3}\:{4}/{5}
(我试过把命令字符串用单引号、双引号、不带引号、不带\u0020、...)
正在使用 MessageFormat 填充
{0} = '\"C:/Program\u0020Files\u0020(x86)/ICW/bin/scp.exe\"'
{1} = 文件名
{2} = scp 用户名
{3} = scp hist IP 地址
{4} = 远程主机上的目标路径
{5} = 文件名(参见{1})
SFTP目前没有选项,只有SCP安装在Windows机器和远程Linux主机上。 如果我在这样做时完全误解了,我将不胜感激任何知识转移以学习如何以正确的方式做到这一点。 :-)
您显然是在尝试启动从 本地 Windows 机器到 远程 Linux[=36] 的 SCP 文件传输=]机.
但是您的代码所做的是,它通过 ssh 连接到 远程 Linux 机器并尝试使用 运行 Windows 样式的命令C:\Program Files (x86)\ICW\bin\scp.exe
那里。那不行,不管你用什么报价。
不要使用 SCP,这是一个古老的协议。使用 SFTP。所有 Linux 台机器都支持 SFTP。 JSch 也有对 SFTP 的本地支持。您不需要任何本地 OpenSSH 安装。
即使您决定坚持使用 SCP,将 JSch SSH/SFTP 库与本地独立 SCP 客户端结合使用也没有任何意义。
要么使用本机 Java SCP 实现:
http://www.jcraft.com/jsch/examples/ScpTo.java.html
(并且您不需要本地 OpenSSH 安装)或 运行
scp.exe
在本地(并且您不需要 JSch SSH 库)- 尽管我根本不推荐此选项。
好的,Martin,谢谢你指引我正确的方向。可能我会检查并尝试使用 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();
}
}