Bash在Java中未正确执行

Bash在Java中未正确执行,java,bash,Java,Bash,我正在编写一个Java程序,需要从系统的/dev/uradom接口提取一个32个字符的密钥。为此,我使用以下过程: public String generateKey() { try { Runtime run = Runtime.getRuntime(); Process pr = run.exec("tr -cd '[:alnum:]' < /dev/urandom | fold -

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

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";
            }
    }

虽然严格来说这不是必需的,但为了运行具有多个命令行参数的程序,需要创建一个字符串数组,该数组由命令组成,作为第一个参数,每个空格都应该是数组的一个条目,例如ls-l

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

这将正确调用命令行。以下是javadoc:

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

进程pr=run.exectr-cd'[:alnum:'
管道|和重定向如用户变量所示,尝试在实际的Unix shell中运行命令;并确保shell作为交互式shell sh-i-c“cmd1 | cmd2”被调用

否则,UNIX管道机制似乎会被阻塞,因为tr一直从/dev/uradom读取数据,但出于某种原因拒绝写入其标准输出

在Terminal.app中执行,但以下命令运行时没有任何停顿:

sh-c'LC|ALL=c tr-cd[:alnum:][/dev/uradom | fold-w30 | head-n1;回声;'

另一种方法是显式限制从/dev/uradom读取的字节数,请参见下面的代码

/*

# 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);
        }
    }
}

只是不要在最小的测试用例中捕获异常。。不需要处理柠檬核。你说的“不捕捉异常”是什么意思?如果我删除try/catch块,编译器会对我大喊大叫。我想你的意思是不同的…请仔细阅读检查异常-这可能是如此令人讨厌的生物-和抛出条款。如果这不适合其他方式,例如更大的上下文,只需将其包装为未经检查的:try{..}catch Exception ex{throw new RuntimeExceptionex;}。这与普通日志记录的区别在于,这仍然会向上传播异常!仅当与异常相关的某些有用内容可能在案例中禁止异常时才禁止异常,但在这里/在测试案例中不允许。为什么必须使用shell?为什么不使用标准的java文件io机制从/dev/uradom中读取32个字符呢?它从不抛出RuntimeException,因此,正如我所想,它本身不会抛出异常。我认为该命令没有像在常规bash shell中那样返回,或者没有正确读取。或者简单的Runtime.getRuntime.execls,-lnot不一定要返回。Runtime.exec/bin/echo XXX工作正常。该示例中没有。它抛出的原因是:java.io.IOException:java.io.IOException:error=2,如果我尝试使用tr语法,就没有这样的文件或目录。如果我将tr替换为/usr/bin/tr,它工作得很好
String[] command = {"ls" , "-l"};
Runtime.getRuntime().exec(command);
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);
        }
    }
}
/*

# 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);
        }
    }
}