I have a Java class called InputTxt and it has an int attribute id. I want to write a shell script that creates a file with id as the file name.
NOTE: The java function that calls this script returns something other than the id.
Just pass the id as a parameter to the script:
import java.io.*;
class InputTxt {
static int id;
public static void main (String[] args) throws IOException {
id = args.length;
try {
Process p = Runtime.getRuntime().exec(
new String[]{"touch", Integer.toString(id)});
} catch (IOException e) {
throw e;
}
}
}
Sample run:
$ javac InputTxt.java
$ java InputTxt 4 5 6
$ ls
3 InputTxt.class InputTxt.java
Related
I've been messing about with the java process API and ran into the following case:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
var command = "echo foo";
System.out.println(command);
run(command);
command = "bash -c 'echo bar'";
System.out.println(command);
run(command);
}
public static void run(String command) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
var br = new BufferedReader(new InputStreamReader(p.getInputStream()));
br.lines().forEach(System.out::println);
}
}
Why does bar not print? I've also tried other commands like systemctl poweroff and mkdir, but none seem to execute. I've also experimented with nohup, which works on its own but not with bash -c.
You call exec(String), which in turn calls exec(String,String,File), which in turn uses a StringTokenizer to chop the command line passed as a single string into an argument list, and then calls exec(String[],String,File).
However, that tokenizer just chops at spaces (it doesn't know that it's working with a command line or what shell would be involved). That means you end up with these tokens as the command: bash, -c, 'echo, foo' --- note the single quotes; Runtime.exec does not involve a shell to handle quotes (or variable substitution or such).
bash then complains about the 'echo, but you don't see that cause you only print the child process' stdout, but not stderr. Add code like this to run:
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("stderr:");
br.lines().forEach(System.out::println);
This gets me:
stderr:
bar': -c: line 1: unexpected EOF while looking for matching `''
bar': -c: line 2: syntax error: unexpected end of file
Now if you remove the single quotes from the call, you just get a single empty line because bash -c expects only one argument to run, which here is the echo, which prints a new line.
To fix this, you need to call the exec version that takes a String[] directly so that you control what is one argument:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
run("echo", "foo");
run("bash", "-c", "echo bar");
}
public static void run(String... command) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
var br = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println("stdout:");
br.lines().forEach(System.out::println);
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("stderr:");
br.lines().forEach(System.out::println);
}
}
Personally, I'd use something higher level like the standard ProcessBuilder class or the exec library from Apache Commons instead, as they have better support for building complicated commands to execute:
import java.io.IOException;
import org.apache.commons.exec.*;
public class ExecDemo {
// Build and execute a command with Apache Commons Exec
private static void demoApacheExec()
throws IOException, ExecuteException {
var cmd = new CommandLine("sh");
cmd.addArgument("-c");
cmd.addArgument("echo test 1", false);
System.out.println("Command: " + cmd);
var executor = new DefaultExecutor();
executor.execute(cmd);
}
// Build and execute a command with ProcessBuilder
private static void demoProcessBuilder()
throws IOException, InterruptedException {
// Can also take a List<String> of arguments
var pb = new ProcessBuilder("sh", "-c", "echo test 2").inheritIO();
System.out.println("Command: " + pb.command());
pb.start().waitFor();
}
public static void main(String[] args) {
try {
demoApacheExec();
demoProcessBuilder();
} catch (Exception e) {
System.err.println("Error executing program: " + e);
System.exit(1);
}
}
}
The important thing is making each argument its own separate thing instead of relying on trying to parse a single string like a shell would (A.C.E has a CommandLine.parse() function, but even it has issues with quoting; addArgument likes to put actual quotes around arguments with spaces in them when it doesn't actually need to unless you tell it not to.).
I have the following short python program "test.py"
n = int(raw_input())
print n
I'm executing the above program from following java program "ProcessRunner.java"
import java.util.*;
import java.io.*;
public class ProcessRunner {
public static void main(String[] args) {
try {
Scanner s = new Scanner(Runtime.getRuntime().exec("python test.py").getInputStream()).useDelimiter("\\A");
System.out.println(s.next());
}
catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
Upon running the command,
java ProcessRunner
I'm not able to pass a value 'n' in proper format to Python program and also the java run hangs. What is the proper way to handle the situation and pass a value to 'n' dynamically to python program from inside java program?
raw_input(), or input() in Python 3, will block waiting for new line terminated input on standard input, however, the Java program is not sending it anything.
Try writing to the Python subprocess using the stream returned by getOutputStream(). Here's an example:
import java.util.*;
import java.io.*;
public class ProcessRunner {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec("python test.py");
Scanner s = new Scanner(p.getInputStream());
PrintWriter toChild = new PrintWriter(p.getOutputStream());
toChild.println("1234"); // write to child's stdin
toChild.close(); // or you can use toChild.flush()
System.out.println(s.next());
}
catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
An alternative is to pass n as a command line argument. This requires modification of the Python script to expect and process the command line arguments, and to the Java code to send the argument:
import java.util.*;
import java.io.*;
public class ProcessRunner {
public static void main(String[] args) {
try {
int n = 1234;
Process p = Runtime.getRuntime().exec("python test.py " + n);
Scanner s = new Scanner(p.getInputStream());
System.out.println(s.next());
}
catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
And the Python script, test.py:
import sys
if len(sys.argv) > 1:
print int(sys.argv[1])
If I understand you correctly you want your java program to pass any output from your python script to System.out and any input into your java program to your python Script, right?
Have a look at the following program to get an idea how you could do this.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ProcessRunner {
public static void main(String[] args) {
try {
final Process process = Runtime.getRuntime().exec("/bin/sh");
try (
final InputStream inputStream = process.getInputStream();
final InputStream errorStream = process.getErrorStream();
final OutputStream outputStream = process.getOutputStream()
) {
while (process.isAlive()) {
forwardOneByte(inputStream, System.out);
forwardOneByte(errorStream, System.err);
forwardOneByte(System.in, outputStream);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void forwardOneByte(final InputStream inputStream,
final OutputStream outputStream)
throws IOException {
if(inputStream.available() <= 0) {
return;
}
final int b = inputStream.read();
if(b != -1) {
outputStream.write(b);
outputStream.flush();
}
}
}
Note This code is just a concept demo. It will eat up your cpu and will not be able to cope with bigger amounts of throughput.
I'm trying toopen/execute another program, which is a .jar file, but I'm getting the following error:
it is not a windows application
(java.io.IOException: CreateProcess error=193)
Here is my code:
import java.io.IOException;
public class Test8 {
public static void main(String[] args) {
try {
String filepath = "C://Users//Alex//Desktop//Speedtest.jar";
Process p = Runtime.getRuntime().exec(filepath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
At the command-line, JARs are executed with java -jar. Try passing a String array:
String[] args = new String[] {"java", "-jar", "/path/to/myJar.jar"};
Process p = Runtime.getRuntime().exec(args);
I am trying to run maven command from java main but it is not working for me as desired.
When i run the below code it runs the maven command on the same existing project in which this main class residing, but i want to run this maven command from this class to any another project folder.
Please help!
Thanks in advance!
package com.codecoverage.runner;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MavenCoberturaRunner {
public static void main(String[] args) throws IOException, InterruptedException {
Process p = null;
try {
p = Runtime.getRuntime().exec("C:/apache-maven-2.0.9/apache-maven-2.0.9/bin/mvn.bat clean cobertura:cobertura -Dcobertura.report.format=xml");
} catch (IOException e) {
System.err.println("Error on exec() method");
e.printStackTrace();
}
copy(p.getInputStream(), System.out);
p.waitFor();
}
static void copy(InputStream in, OutputStream out) throws IOException {
while (true) {
int c = in.read();
if (c == -1)
break;
out.write((char) c);
}
}
}
You should use Runtime.exec(String command, String[] envp, File dir) method,
which executes the specified string command in a separate process with the specified environment and working directory.
What you want is to set working directory so it points to the place you need to run Maven at.
use -f in command line
C:/apache-maven-2.0.9/apache-maven-2.0.9/bin/mvn.bat -f path/to/your/pom.xml clean cobertura:cobertura -Dcobertura.report.format=xml
I am trying to compile a java class file in another java class file by using javac command. It went well if these two file do not have any package name with them.
Class Laj
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Laj {
private static void printLines(String name, InputStream ins) throws Exception {
String line = null;
BufferedReader in = new BufferedReader(
new InputStreamReader(ins));
while ((line = in.readLine()) != null) {
System.out.println(name + " " + line);
}
}
private static void runProcess(String command) throws Exception {
Process pro = Runtime.getRuntime().exec(command);
printLines(command + " stdout:", pro.getInputStream());
printLines(command + " stderr:", pro.getErrorStream());
pro.waitFor();
if(pro.exitValue() != 0){
System.out.println(command + " exitValue() " + pro.exitValue());
}
}
public static void main(String[] args) {
try {
runProcess("javac simpleTest.java");
runProcess("java simpleTest");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Class SimpleTest
public class simpleTest {
public static void main(String[] args) {
System.out.println("What's wrong with it");
}
}
I can use the commands javac Laj.java and java Laj to compile and run them well. However if I add the package name, for example package compileTest in the front of these two classes and modify the runProcess part of the code in Laj to
runProcess("javac -d . compileTest.simpleTest.java");
runProcess("java compileTest.simpleTest");
the code would not work.
Can anyone help me, thank you.
Why do not you use 'JavaCompiler' class to compile your java file. Please see below example I have compiled a java class with package name.
Package Name = com.main
Class Name = MainClass.java
Source Dir = src
public void compileClass() {
System.setProperty("java.home", "G:\\Java\\Tools\\installed\\JDK"); // Set JDK path it will help to get compiler
File root = new File("/src"); // Source Directory
File sourceFile = new File(root, "com/main/MainClass.java"); // Java file name with package
sourceFile.getParentFile().mkdirs();
try {
new FileWriter(sourceFile).close(); // Read Java file
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
System.out.println(compiler.run(null, null, null, sourceFile.getPath()));
}