【问题标题】:Java: Shell commands with redirectionJava:带有重定向的 Shell 命令
【发布时间】:2016-05-16 21:04:26
【问题描述】:

我正在尝试使用 java 在 shell 中执行重定向,但我得到一个空的 file1.txt 命令:ls -all > file1.txt

虽然ls -all被正确执行了。

commandLine 是字符串类型,并且具有我想要执行的命令。
例如String commandLine = "ls -all";

代码片段(这是代码的相关部分):

   StringBuilder output = new StringBuilder();
   Runtime runtime = Runtime.getRuntime();
    Process process = runtime.exec(new String[]{"/bin/sh", "-c", commandLine});
    process.waitFor();

    try {
         BufferedReader reader = 
           new BufferedReader(new InputStreamReader(process.getInputStream()));

          String line;          
          line = "";
          while ((line = reader.readLine())!= null) {
              output.append(line);
              output.append("\n");
          }
    } 
    catch(Exception ex) {
      ex.printStackTrace();
    } 
    finally {
      process.destroy();
    }

最后,我正在处理来自实例 output 的输出。
另外,我想执行类似于curl -v http://www.centos.org > /dev/null 的命令,但这也给了我一个空的响应!

【问题讨论】:

  • commandLine 是什么?
  • 哎呀忘了提。我已经编辑了我的问题以包括 commandLine 是什么!感谢您提出这个问题!
  • > /dev/null 显然会给你一个空的响应,因为这就是人们重定向到 /dev/null 的原因
  • 但是在 bash 上运行相同的命令会给我一个输出。我应该用什么代替 /dev/null 来获得输出?还有,为什么file1.txt是空的
  • 你的意思可能是一个错误?不要将 stdout 与 stderr 混合使用!

标签: java shell ubuntu io-redirection


【解决方案1】:

简答

您正在阅读stdout,它是空的,因为您将stdout 重定向到/dev/null。使用getErrorStream() 而不是getInputStream() 得到stderr

stdoutstderr

每个进程有 2 个输出流,stdoutstderr。在提到的curl -v http://www.centos.org 的情况下,2 个输出流将是以下流:

stdout:

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.6.3</center>
</body>
</html>

stderr:

* Rebuilt URL to: http://www.centos.org/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 85.12.30.226...
* Connected to www.centos.org (85.12.30.226) port 80 (#0)
> GET / HTTP/1.1
> Host: www.centos.org
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.6.3
< Date: Thu, 19 May 2016 15:31:03 GMT
< Content-Type: text/html
< Content-Length: 184
< Connection: keep-alive
< Location: https://www.centos.org/
< 
{ [184 bytes data]
100   184  100   184    0     0   1184      0 --:--:-- --:--:-- --:--:--  1187
* Connection #0 to host www.centos.org left intact

&gt; 运算符将仅重定向 stdout,但 stderr 将保持不变。

在终端中执行

在终端中,您通常会看到 stdoutstderr 混合使用。所以如果你执行curl -v http://www.centos.org &gt; /dev/null,那么stdout会被重定向到/dev/null,但是你仍然会看到stderr的输出。这就是您所观察到的,当您说“在 bash 上运行相同的命令会给出 [...] 输出。

从 Java 执行

另一方面,从 Java 执行命令将使两个流分开。流stdout可以使用process.getInputStream()获取,stderr可以使用process.getErrorStream()获取。

您使用的是前者 (stdout),但由于在您的示例 (curl -v http://www.centos.org) 中 stdout 被重定向到 /dev/null,因此您看不到任何输出也就不足为奇了.

您可以获得的唯一输出是stderr。为此,您必须将 process.getInputStream() 替换为 process.getErrorStream()

file1.txt

您在 cmets 中声明文件 file1.txt 在从 Java 执行类似 ls -all &gt; file1.txt 这样的一些命令后为空。

最可能的原因是ls 的执行实际上失败了,但您看不到错误消息,因为它打印到stderr - 您从未阅读过。您声明相同的命令在终端中可以正常工作,但是执行环境不同(不同的环境变量、不同的工作目录等),这可能会使相同的命令失败。所以请阅读stderr 以获取错误消息。

file1.txt 为空的另一个可能原因是您检查了不同的文件,因为您不知道工作目录。不止一次发生在我身上,我检查了错误的文件!检查时间戳以确保它是正确的文件。

【讨论】:

  • 谢谢,当时我还没有完全理解iostreams和/dev/null。
猜你喜欢
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 2021-11-09
  • 2015-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多