I want to print the output of echo %path% from Java instead of cmd.
I have the following code:
private void getPath() throws IOException {
String getPath = "cmd.exe /C echo %path%";
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(getPath);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String commandOutput = "";
while (commandOutput != null) {
commandOutput = reader.readLine();
System.out.println(commandOutput);
}
}
If I run echo %path% from the cmd the output begins with:
C:\Oracle\Ora11\bin;C:\Oracle\Ora10\bin;C:\Program Files\Common
But the output of the Java program begins with:
C:/Program Files/Java/jre7/bin/client;C:/Program
Files/Java/jre7/bin;C:/Program Files/Java/jre7/lib/i386
and only after this line, the rest of the output is similar.
Why is this happening?
Looks like Java appends to %path% its own paths. Nothing else.
You are probably running your test from IDE (eg Eclipse). Try the same from command line. BTW there is another way to print environnment variables from Java
System.out.println(System.getenv("PATH"));
Related
I try to run Linux shell command from Java. The commands work fine directly on the shell, but one always crash.
I have a makefile and I try to run the make through Java.
My Java code:
String command = "make generate FILE=" + name ;
String [] envp = { } ;
File dir = new File ( System.getProperty("user.dir")) ;
Process proc = Runtime.getRuntime().exec(command,envp,dir);
proc.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
My makefile:
generate:
llvm-as -f VSOP_Executable/$(FILE).ll -o $(FILE).bc
llc $(FILE).bc
gcc -c $(FILE).s -o $(FILE).o
gcc $(FILE).o -o $(FILE) -no-pie
It always crash at the last line, where I try to generate an executable.
The error:
makefile:47: recipe for target 'generate' failed
Solved as Paul Hicks wrote in his comment. The reason was clearing all environment variables.
I changed the code and removed the empty envp. It seems to work now.
String cmd = "make generateVSOP FILE=" + name;
Runtime run = Runtime.getRuntime();
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);
}
I searched a lot but did not find the solution.
My goal is using java to call commands and get output in windows and linux. I found Runtime.exec method and did some experiments.
Everything went ok except when there's space in the command parameters.
Test code as below, also in github.
The code works well on windows, but in linux, output is empty:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
try {
Runtime rt = Runtime.getRuntime();
String[] commandArray;
if (isWindows()) {
commandArray = new String[]{"cmd", "/c", "dir", "\"C:\\Program Files\""};
} else {
commandArray = new String[]{"ls", "\"/root/a directory with space\""};
}
String cmd = String.join(" ",commandArray);
System.out.println(cmd);
Process process = rt.exec(commandArray);
BufferedReader input = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String result = "";
String line = null;
while ((line = input.readLine()) != null) {
result += line;
}
process.waitFor();
System.out.println(result);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static boolean isWindows() {
String OS = System.getProperty("os.name").toLowerCase();
return (OS.indexOf("win") >= 0);
}
}
if I execute the printed command in bash directly, then the output is as expected.
[root#localhost javatest]# javac Main.java
[root#localhost javatest]# java Main
ls "/root/a directory with space"
[root#localhost javatest]# ls "/root/a directory with space"
a.txt b.txt
[root#localhost javatest]#
Can anyone explain why and give ways to solve?
There are two versions of exec.
exec(String command)
Here you specify a command in a similar way to how you would do it on the command-line, i.e. you need to quote arguments with spaces.
cmd /c dir "C:\Program Files"
exec(String[] cmdarray)
Here you specify the arguments separately, so the arguments are given as-is, i.e. without quotes. The exec method will take care of any spaces and quote-characters in the argument, correctly quoting and escaping the argument as needed to execute the command.
cmd
/c
dir
C:\Program Files
So, remove the extra quotes you added:
if (isWindows()) {
commandArray = new String[] { "cmd", "/c", "dir", "C:\\Program Files"};
} else {
commandArray = new String[] { "ls", "/root/a directory with space"};
}
I want to set and echo a Windows variable in Java:
public static void main(String[] args) throws IOException
{
Runtime rt = Runtime.getRuntime();
String[] cmd = { "cmd.exe", "/c", "set HOSTNAME=%COMPUTERNAME% "
+ "&& echo %HOSTNAME%" };
Process proc = rt.exec(cmd);
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
System.out.println("Output:\n");
String s = null;
while ((s = stdInput.readLine()) != null)
{
System.out.println(s);
}
System.out.println("Error (if any):\n");
while ((s = stdError.readLine()) != null)
{
System.out.println(s);
}
}
I expect the program will print out my computer host name or I will use this value for another purpose. But the output is just like this:
Output:
%HOSTNAME%
Error (if any):
How could I get the value that I have set in the command set HOSTNAME=%COMPUTERNAME%
It's irrelevant to Java because it's how cmd parses the command. The whole command will be parsed at once for variable expansion. At the time the command is parsed the variable is not yet available, so it'll be replaced with nothing in a batch file or leave as-is in command line
You need to use delayed expansion and print the variable with !!
cmd.exe /V:ON /c set HOSTNAME=%COMPUTERNAME% && echo !HOSTNAME!
The /V:ON is for enabling delayed expansion
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
...
/V:ON Enable delayed environment variable expansion using ! as the
delimiter. For example, /V:ON would allow !var! to expand the
variable var at execution time. The var syntax expands variables
at input time, which is quite a different thing when inside of a FOR
loop.
In a batch file it can be enabled by setlocal EnableDelayedExpansion
However for that purpose just cmd.exe /V:ON /c echo %COMPUTERNAME% is enough. Yet it's still not the efficient way. There are better ways to get hostname in Java
Map<String, String> env = System.getenv();
if (env.containsKey("COMPUTERNAME"))
return env.get("COMPUTERNAME");
or
InetAddress.getLocalHost().getHostName()
Your syntax for running two commands at once is wrong. Try using a single & in the command line instead of &&.
The real problem, I think, is that cmd.exe does all variable substitution before executing the command line (including parsing the &&). When it finds the syntax %HOSTNAME% for a variable that doesn't exist (yet), it leaves the text as is: %HOSTNAME%. So try issuing two commands to the same process, followed by an exit command.
Another approach is to change the command to:
set HOSTNAME=%COMPUTERNAME% & SET HOSTNAME
Then you will get back the string "HOSTNAME=my_computer_name", from which you can strip out the leading "HOSTNAME=" prefix.
I am getting an exception like java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory while executing the command below despite that there are no issues when I execute the same command through the terminal. I need to execute and return the output of the command below:
cat /home/talha/* | grep -c TEXT_TO_SEARCH
Here is the method used to execute commands using 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();
}
Runtime.exec does not use a shell (like, say, /bin/bash); it passes the command directly to the operating system. This means wildcards like * and pipes (|) will not be understood, since cat (like all Unix commands) does not do any parsing of those characters. You need to use something like
p = new ProcessBuilder("bash", "-c", command).start();
or, if for some bizarre reason you need to stick to using the obsolete Runtime.exec methods:
p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });
If you are only running that cat/grep command, you should consider abandoning the use of an external process, since Java code can easily traverse a directory, read lines from each file, and match them against a regular expression:
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();
}
}
Update: To recursively read all files in a tree, use 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();
}
};
}
$PATH is an environment variable that tells the system where to search for executable programs (it's a list of directories separated by colons). It is usually set in your .bashrc or .cshrc file but this is only loaded when you log in. When Java runs, $PATH is likely not set because the rc file is not executed automatically, so the system can't find programs without specifying exactly where they are. Try using /bin/cat or /usr/bin/cat instead of just cat and see if it works. If it does, $PATH is your problem. You can add $PATH=/bin:/usr/bin to your script or just leave it with the directory name specified (e.g. /bin/cat).
Just because you can execute it in a login session doesn't mean it will work the same when a daemon like your Java program runs. You have to know what's in your .bashrc or .cshrc file and even sometimes how the system file is written (/etc/bashrc) in order to know how to write a script that runs under a daemon. Another consideration is that daemons often run under the context of a different user, and that throws things off, too.
I am writing a java program that needs to execute shell commands, so I wrote a function that would take the command to execute as a string (ie: "mkdir ~/Folder1") and execute that command with the shell. Here is the function:
private static void shell(String cmd)
{
try
{
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line = buf.readLine()) != null) {
System.err.println(line); // show any errors returned by the command executed on the error console
}
} catch (Exception ee) {}
}
for some weird reason this function is not executing any commands. Did I do this wrong? It seems like a simple thing to execute shell commands, but it is not working.
I think you are passing the command string as some mkdir command like ,
"mkdir C:\some\folder\path".
mkdir is not some binary in Windows path, it's a parameter to command line.
Use the command string as "cmd.exe /c mkdir C:\some\folder\path"
Then it should work fine.