我试图通过Java应用程序将密码管道输入smbpassword,这是我通过终端管道的方式:
(echo newPassword; echo confirmPassword) | smbpasswd -a -s client1
并且输出显示命令很好:
Added user client1
但是,我无法通过Java应用程序实现这一点,这里是我使用的代码:
public void run(String command, String[] prompt) {
try {
String[] args = new String[] {"/bin/bash","-c","echo " + rootPassword + "| sudo -S " + command};
Process proc = new ProcessBuilder(args).start();
if (prompt != null && prompt.length > 0) {
for (int i = 0; i < prompt.length; i++) {
proc.getOutputStream().write((prompt[i] + "\r\n").getBytes());
proc.getOutputStream().flush();
}
}
proc.waitFor();
String output = "";
String line;
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
output += line + "\n";
}
System.out.println(output);
input.close();
}
catch (Exception ex) {
System.out.println(null, ex.getMessage());
}
}
我尝试使用OutputStream:
String[] pipe = { password, password };
run("smbpasswd -s -a " + username, pipe);
或管道:
run("(echo " + password + "; echo " + password + ") | smbpasswd -s -a " + username, null);
但两个都不起作用,我没有输出,并且我通过pdbedit -L
检查后似乎没有创建用户。但是,我能够通过该函数使用管道(例如echo username:password | chpasswd
)执行另一个命令。
任何想法?
提前谢谢。
答案 0 :(得分:0)
主要的概念问题是shell代码,例如您正在尝试运行:
(echo newPassword; echo confirmPassword) | smbpasswd -a -s client1
不是sudo
所要求的“命令”。事实上,即使在shell术语中,它也不是“命令”;相反,它是一个管道,由复合命令和简单命令组成。 sudo
希望您提供一个简单的命令。
但这实际上有点搁置。您的问题并非真正针对sudo
;相反,这是一个shell问题。在失败的情况下,您的run()
方法调用bash
来执行以下shell代码:
echo rootPassword | sudo -S (echo newPassword; echo confirmPassword) | smbpasswd -a -s client1
这至少有两个原因:
子shell调用不能出现在这样的简单命令(即sudo
)参数列表中。您可以在那里放置一个命令替换($(echo ...)
),但这不符合您的目的,因为内部换行符不会被保留。
即使您解决了(1),您的第二个管道处于错误的级别:它会将sudo
的输出传输到smbpasswd
。这在数据方面很好,但它会让smbpasswd
无特权地运行 - sudo
不适用于它。
您可以通过指示sudo
通过shell运行代码来解决问题。您可以通过在内部bash -c
命令中嵌入最终命令来实现这一点,但使用。如果要在Java源代码中的单个String中编码整个操作,那么这些内容可能是最常用的解决方案:sudo
的{{1}}选项可能更容易(但要注意{{1}如果允许,可以选择与-s
不同的shell
<击> 撞击>
<击>-s
击> <击> 撞击>
bash
然而,您的大部分问题都源于您依靠 String[] args = new String[] { "/bin/bash", "-c",
"echo " + rootPassword + " | sudo -S -s '" + command + "'" };
向您的命令提供数据。您应该考虑使用 String[] args = new String[] { "/bin/bash", "-c",
"echo " + rootPassword + " | sudo -S bash -c '" + command + "'" };
的{{1}}来从Java程序向其提供数据。这不仅仅是一个简单的Java端API,但我认为你在欺骗自己的API有多简单。正如您所发现的那样,它隐藏了陷阱,即使我上面提供的修订版仍然至少有一个:如果提交给它的命令包含单引号字符(echo
),它可能会中断。
以下是通过Process
:
OutputStream
您可以在其类中使用
'
请特别注意,在您编写了要写入的所有内容之后,OutputStream
的输出流通常必须关闭。如果您不这样做,您可以运行的某些命令将不会退出。
还请注意
对于一般情况,您必须阅读每个 public void run2(String command, String commandInput)
throws IOException, InterruptedException {
String[] args = new String[] { "sudo", "-S", "bash", "-c", command };
Process proc = new ProcessBuilder(args).start();
Writer toProc = new OutputStreamWriter(proc.getOutputStream());
toProc.write(rootPassword, 0, rootPassword.length());
toProc.write('\n');
toProc.write(commandInput, 0, commandInput.length());
toProc.close();
proc.waitFor();
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = input.readLine()) != null) {
output.append(line).append('\n');
}
System.out.println("Command output:");
System.out.println(output.toString());
input.close();
}
的输入流和错误流(或者只有前者,如果您将它们组合在一起),并行与流程本身。如果您还没有组合流,那么您必须彼此并行读取它们。如果您正在写入流程的输出流,那么它也必须并行。如果您没有安排通过自己的线程处理每个流,那么该进程可能会卡住。
另一方面,你不需要一个单独的线程来运行run2("smbpasswd -a -s client1", "newPassword\nnewPassword");
本身 - 毕竟,它代表了一个完整的独立过程。只需推迟等待它,直到您关闭其输出流并读取其输入和错误流的结束。