Bash在Java中没有正确执行

时间:2013-01-09 00:06:02

标签: java bash

我正在编写一个需要从系统的/ dev / urandom接口中提取32个字符的Java程序。为此,我使用以下程序:

public String generateKey() {
            try {
                    Runtime run = Runtime.getRuntime();
                    Process pr = run.exec("tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1;echo;");
                    pr.waitFor();
                    BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
                    StringBuffer sb = new StringBuffer();
                    String line = "";
                    while ((line = buf.readLine())!= null ) {
                            sb.append(line);
                    }
                    return sb.toString();
            } catch (Exception e) {
                    e.printStackTrace();
                    return "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
            }
    }

(如果它不能这样做那么它将返回一堆空字符)

由于某种原因,它没有返回任何内容(或抛出异常而不打印堆栈跟踪)。我知道这是因为我将它打印到控制台(没有),当我把它交给我的RC4引擎时,它会抛出零除错误。为什么命令不起作用,我怎么能让它工作?

感谢您的帮助。

编辑:我发布此消息后不到两分钟我推断它没有返回空字符,因为我将其设置为返回单词“lemons”并且它做了同样的事情所以它不会抛出异常。

编辑2:根据评论中的建议,我试图直接从文件中读取相同的结果,但我想我可能做错了...

File file = new File("/dev/urandom");
            FileReader freader = null;
            StringBuffer sb = new StringBuffer();
            int x = 0;
            try {
                    freader = new FileReader(file);
                    BufferedReader reader = new BufferedReader(freader);
                    for (int i=0;(i<32||(x=reader.read())==-1);i++) {
                            sb.append((char) x);
                    }
            return sb.toString();
            } catch(Exception e) {
                    e.printStackTrace();
                    return "a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
            }

编辑3 :这可能有助于帮助: 使用上面的代码并输出到od我发现它只是读取0。 (同样,它不会抛出异常,否则它不会全是零)。

# ./run.sh | od
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*

4 个答案:

答案 0 :(得分:4)

  

Process pr = run.exec("tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1;echo;");

管道(|)和重定向(<)由shell处理,而不是OS。您可以通过将整个命令作为字符串参数传递给sh来解决这个问题。请参阅以下示例并对其进行调整以供您使用:

import java.io.*;
class P1 {
    public static void main(String[] args) throws Exception {
        Runtime run = Runtime.getRuntime();
        Process pr = run.exec("sh -c \"ls </dev/null | grep java\"");
        pr.waitFor();
        BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line;
        while ((line = buf.readLine())!= null ) {
            System.out.println(line);
        }
    }
}

修改

虽然以上内容可能会帮助您运行使用重定向的shell命令,但在当前实例中,正确的方法是根本不使用外部进程,而是直接从/dev/urandom读取,正如@Josh Cartwright在{{ 3}}

答案 1 :(得分:2)

虽然这不是绝对必要的,但是为了运行具有多个命令行参数的程序,您需要创建一个由命令组成的字符串数组作为第一个参数,并且每个空格应该是数组的一个条目, ls -l <​​/ p>的示例

String[] command = {"ls" , "-l"};
Runtime.getRuntime().exec(command);

这样可以正确调用命令行。这是javadoc:Exec javadoc

答案 2 :(得分:1)

执行Runtime.exec()时,不能使用linux管道来运行多个commans。您应该单独运行命令或手动处理tr命令的结果。除此之外,您必须使用完整路径来命令二进制文件,例如将tr替换为/usr/bin/tr

答案 3 :(得分:1)

正如用户Miserable Variable已经指出的那样,尝试在实际的Unix shell中运行命令;并确保将shell作为交互式shell(sh -i -c 'cmd1 | cmd2')进行调用。

否则UNIX管道机制似乎被阻止,因为tr不断读取/dev/urandom,但由于某种原因拒绝写入stdout

Terminal.app中执行但以下命令运行没有任何打嗝:

sh -c 'LC_ALL=C tr -cd [:alnum:] < /dev/urandom | fold -w30 | head -n1; echo;'

另一种方法是明确限制从/dev/urandom读取的字节数(参见下面的代码)。

/*

# cat GenerateKey.java
javac GenerateKey.java
java GenerateKey

# For more information see the "Java exec and Unix pipes" comment in:
# "Java exec - execute system processes with Java ProcessBuilder and Process (part 3)",
# http://alvinalexander.com/java/java-exec-processbuilder-process-3

*/

import java.io.*;
import java.util.*;

public class GenerateKey {
    public static void main(String[] args) throws Exception {
        Runtime run = Runtime.getRuntime();

        // does not work on Mac OS X 10.6.8
        //String[] cmd = { "/bin/sh", "-c", "LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1; echo;" };  

        // works
        String[] cmd = { "/bin/sh", "-i", "-c", "LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1; echo;" };  
        //String[] cmd = { "/bin/sh", "-c", "head -c 3000 < /dev/urandom | LC_ALL=C tr -cd '[:alnum:]' | head -c 30" }; 
        //String[] cmd = { "/bin/sh", "-c", "dd if=/dev/urandom bs=3000 count=1 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]' | fold -w30 | head -n1" }; 
        Process pr = run.exec(cmd);

        pr.waitFor();
        BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line;
        while ((line = buf.readLine())!= null ) {
            System.out.println(line);
        }
    }
}