java.lang.Runtime 异常 "Cannot run program"
java.lang.Runtime exception "Cannot run program"
我在执行下面的命令时遇到类似 java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory
的异常,尽管 当我通过终端执行相同的命令时没有问题。 我需要执行并 return 以下命令的输出:
cat /home/talha/* | grep -c TEXT_TO_SEARCH
这里是使用Runtime
执行命令的方法 class:
public static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
$PATH
是一个环境变量,它告诉系统在哪里搜索可执行程序(它是由冒号分隔的目录列表)。它通常在您的 .bashrc
或 .cshrc
文件中设置,但这仅在您登录时加载。当 Java 运行s 时,可能未设置 $PATH
因为 rc
文件不会自动执行,所以系统无法在不指定确切位置的情况下找到程序。尝试使用 /bin/cat
或 /usr/bin/cat
而不是 cat
看看它是否有效。如果是这样,$PATH
就是你的问题。您可以将 $PATH=/bin:/usr/bin
添加到您的脚本中,或者只保留指定的目录名称(例如 /bin/cat
)。
仅仅因为您可以在登录会话中执行它并不意味着它在像您的 Java 程序 运行s 这样的守护程序时也能正常工作。您必须知道 .bashrc
或 .cshrc
文件中的内容,甚至有时系统文件的写入方式 (/etc/bashrc
) 才能知道如何编写 运行 的脚本在守护进程下。另一个考虑因素是,守护进程通常 运行 在不同用户的上下文中,这也会引发问题。
Runtime.exec 不使用 shell(比如 /bin/bash
);它将命令直接传递给操作系统。这意味着像 *
和管道 (|
) 这样的通配符将不会被理解,因为 cat
(像所有 Unix 命令一样)不会对这些字符进行任何解析。你需要使用像
这样的东西
p = new ProcessBuilder("bash", "-c", command).start();
或者,如果出于某些奇怪的原因您需要坚持使用过时的 Runtime.exec 方法:
p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });
如果你只是运行那个cat/grep命令,你应该考虑放弃使用外部进程,因为Java代码可以很容易地遍历一个目录,从每个目录中读取行文件,并将它们与正则表达式匹配:
Pattern pattern = Pattern.compile("TEXT_TO_SEARCH");
Charset charset = Charset.defaultCharset();
long count = 0;
try (DirectoryStream<Path> dir =
Files.newDirectoryStream(Paths.get("/home/talha"))) {
for (Path file : dir) {
count += Files.lines(file, charset).filter(pattern.asPredicate()).count();
}
}
更新:要递归读取树中的所有文件,请使用Files.walk:
try (Stream<Path> tree =
Files.walk(Paths.get("/home/talha")).filter(Files::isReadable)) {
Iterator<Path> i = tree.iterator();
while (i.hasNext()) {
Path file = i.next();
try (Stream<String> lines = Files.lines(file, charset)) {
count += lines.filter(pattern.asPredicate()).count();
}
};
}
我在执行下面的命令时遇到类似 java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory
的异常,尽管 当我通过终端执行相同的命令时没有问题。 我需要执行并 return 以下命令的输出:
cat /home/talha/* | grep -c TEXT_TO_SEARCH
这里是使用Runtime
执行命令的方法 class:
public static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
$PATH
是一个环境变量,它告诉系统在哪里搜索可执行程序(它是由冒号分隔的目录列表)。它通常在您的 .bashrc
或 .cshrc
文件中设置,但这仅在您登录时加载。当 Java 运行s 时,可能未设置 $PATH
因为 rc
文件不会自动执行,所以系统无法在不指定确切位置的情况下找到程序。尝试使用 /bin/cat
或 /usr/bin/cat
而不是 cat
看看它是否有效。如果是这样,$PATH
就是你的问题。您可以将 $PATH=/bin:/usr/bin
添加到您的脚本中,或者只保留指定的目录名称(例如 /bin/cat
)。
仅仅因为您可以在登录会话中执行它并不意味着它在像您的 Java 程序 运行s 这样的守护程序时也能正常工作。您必须知道 .bashrc
或 .cshrc
文件中的内容,甚至有时系统文件的写入方式 (/etc/bashrc
) 才能知道如何编写 运行 的脚本在守护进程下。另一个考虑因素是,守护进程通常 运行 在不同用户的上下文中,这也会引发问题。
Runtime.exec 不使用 shell(比如 /bin/bash
);它将命令直接传递给操作系统。这意味着像 *
和管道 (|
) 这样的通配符将不会被理解,因为 cat
(像所有 Unix 命令一样)不会对这些字符进行任何解析。你需要使用像
p = new ProcessBuilder("bash", "-c", command).start();
或者,如果出于某些奇怪的原因您需要坚持使用过时的 Runtime.exec 方法:
p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });
如果你只是运行那个cat/grep命令,你应该考虑放弃使用外部进程,因为Java代码可以很容易地遍历一个目录,从每个目录中读取行文件,并将它们与正则表达式匹配:
Pattern pattern = Pattern.compile("TEXT_TO_SEARCH");
Charset charset = Charset.defaultCharset();
long count = 0;
try (DirectoryStream<Path> dir =
Files.newDirectoryStream(Paths.get("/home/talha"))) {
for (Path file : dir) {
count += Files.lines(file, charset).filter(pattern.asPredicate()).count();
}
}
更新:要递归读取树中的所有文件,请使用Files.walk:
try (Stream<Path> tree =
Files.walk(Paths.get("/home/talha")).filter(Files::isReadable)) {
Iterator<Path> i = tree.iterator();
while (i.hasNext()) {
Path file = i.next();
try (Stream<String> lines = Files.lines(file, charset)) {
count += lines.filter(pattern.asPredicate()).count();
}
};
}