我编写了一个简单的 Java 程序来打印文件的第一行 -
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
public class ReadFirstLine
{
public static void main(String[] args) throws Exception
{
String filename = args[0];
BufferedReader iR = new BufferedReader (new FileReader(filename));
BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));
outputWriter.write(iR.readLine());
iR.close();
oW.close();
}
}
然后,我在 /usr/bin 目录中创建了一个名为的符号链接ReadFirstLine
,它指向 /usr/local/RFL/ReadFirstLine 脚本 -
#! /bin/bash
java -cp "/usr/local/RFL" ReadFirstLine "$1"
(/usr/local/RFL 有 ReadFirstLine.class)
现在,我可以从任何目录调用 ReadFirstLine,如下所示 -
$ ReadFirstLine simplefile.txt
我想从不同的机器调用同一个脚本。所以从远程机器我尝试 -
$ ssh username@xyz ReadFirstLine < localfile.txt
但是,我收到了错误
Exception in thread "main" java.io.FileNotFoundException: (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at java.io.FileInputStream.<init>(FileInputStream.java:101)
at java.io.FileReader.<init>(FileReader.java:58)
at ReadFirstLine.main(ReadFirstLine.java:12)
如何修改 Java 程序/脚本以使此远程调用有效?
答案1
我对 Java 一无所知,但我可以向您展示概念证明。说我们有本地文件.txt:
Here is the local file.
在远程机器上,我们有远程.sh:
#!/bin/bash
cat /dev/stdin
请注意,远程计算机上的脚本调用一个程序,该程序读取自 stdin
。然后传递内容本地文件.txt到你的 ssh 命令:
user@local:~$ cat localfile.txt | ssh user@remote remote.sh
Here is the local file.
您的 Java 程序正在尝试读取文件远程计算机上不存在该文件。我想你可以尝试模仿本地文件。
改变远程.sh到:
#!/bin/bash
cat "$@"
并调用它
user@local:~$ cat localfile.txt | ssh user@remote 'remote.sh <(cat /dev/stdin)'
Here is the local file.
我认为将 Java 程序中的该部分更改为从stdin
.
我猜测事情可能会变得混乱如果本地文件.txt包含任何可能被 shell 解释为可扩展的内容(例如*
),但这需要您自己弄清楚。
答案2
问题在于 shell 重定向 (<) 通过 ssh 隧道发送文件。 Java 类需要的不是文件,而是带有本地文件“文件名”的字符串,该文件将用 FileReader 读取。
不将文件名传递给 FileReader,而是从标准输入读取。
InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR = new BufferedReader (isReader);
以此作为参考: https://stackoverflow.com/questions/5724646/how-to-pipe-input-to-java-program-with-bash
现在你的班级将是:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
public class ReadFirstLine
{
public static void main(String[] args) throws Exception
{
String filename = args[0];
System.out.println(filename);
//BufferedReader iR = new BufferedReader (new FileReader(filename));
InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR = new BufferedReader (isReader);
BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));
//outputWriter.write(iR.readLine());
System.out.println(iR.readLine());
iR.close();
oW.close();
}
}
但对于这个任务我肯定会使用:
head -1 filename.txt
:)
答案3
根据定义,本地文件位于您的本地计算机上。 java 程序位于远程计算机上。远程计算机不知道您的本地文件,并且在任何生产情况下都可能没有读取它的权限。对于这种情况,我可以想到三种一般方法:
1) 将 Java 程序更改为从 stdin 读取而不是从文件读取。然后你当前的语法$ ssh username@xyz ReadFirstLine < localfile.txt
就可以工作了。
2) 在运行java程序之前,将文件从本地计算机scp到远程计算机。 scp localfile.txt username@xyz 确保将其放入 java 程序的工作目录中。
3) 将远程计算机中的远程目录挂载到本地计算机。这是最接近您所要求的设置的解决方案。它将允许您在本地更改文件,远程计算机将看到更改。有关安装远程目录的更多信息,请参阅此答案。
java 程序的参数将是路径正如远程计算机上显示的那样。
在本地计算机上:/directory/which/has/been/shared/localfile.txt
在远程计算机上:/path/to/mounted/directory/on/remote/host/localfile.txt
$ ssh username@xyz ReadFirstLine < /path/to/mounted/directory/on/remote/host/localfile.txt
答案4
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
public class ReadFirstLine
{
public static void main(String[] args) throws Exception
{
String filename = args[0];
BufferedReader iR = new BufferedReader (new FileReader(filename));
BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));
outputWriter.write(iR.readLine());
iR.close();
oW.close();
}
}