So I have a Java console jar that works with commands that I enter while its running.
Is this also possible with PHP? I know executing the jar is, with exec(), but I can't really pass the running jar commands or get its output.
What you'll want to do is initialize the jar with proc_open() instead of exec(). proc_open() allows you to have individual streams to read/write from/to the stdin/stdout/stderr of your Java process. So, you'll start the Java process, and then you'll use fwrite() to send commands to the stdin ($pipes[0]) of the Java process. See the examples on proc_open()'s documentation page for more info.
EDIT Here's a quick code sample (just a lightly modified version of the example on the proc_open docs):
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
);
$process = proc_open('java -jar example.jar', $descriptorspec, $pipes);
if (is_resource($process)) {
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /tmp/error-output.txt
fwrite($pipes[0], 'this is a command!');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo "command returned $return_value\n";
}
Related
I'm trying to execute bash script using karate. I'm able to execute the script from karate-config.js and also from .feature file. I'm also able to pass the arguments to the script.
The problem is, that if the script fails (exits with something else than 0) the test execution continues and finishes as succesfull.
I found out that when the script echo-es something then i can access it as a result of the script so I could possibly echo the exit value and do assertion on it (in some re-usable feature), but this seems like a workaround rather than a valid clean solution. Is there some clean way of accessing the exit code without echo-ing it? Am I missing on something?
script
#!/bin/bash
#possible solution
#echo 3
exit 3;
karate-config.js
var result = karate.exec('script.sh arg1')
feture file
def result = karate.exec('script.sh arg1')
Great timing. We very recently did some work for CLI testing which I am sure you can use effectively. Here is a thread on Twitter: https://twitter.com/maxandersen/status/1276431309276151814
And we have just released version 0.9.6.RC4 and new we have a new karate.fork() option that returns an instance of Command on which you can call exitCode
Here's an example:
* def proc = karate.fork('script.sh arg1')
* proc.waitSync()
* match proc.exitCode == 0
You can get more ideas here: https://github.com/intuit/karate/issues/1191#issuecomment-650087023
Note that the argument to karate.fork() can take multiple forms. If you are using karate.exec() (which will block until the process completes) the same arguments work.
string - full command line as seen above
string array - e.g. ['script.sh', 'arg1']
json where the keys can be
line - string (OR)
args - string array
env - optional environment properties (as JSON)
redirectErrorStream - boolean, true by default which means Sys.err appears in Sys.out
workingDir - working directory
useShell - default false, auto-prepend cmd /c or sh -c depending on OS
And since karate.fork() is async, you need to call waitSync() if needed as in the example above.
Do provide feedback and we can tweak further if needed.
EDIT: here's a very advanced example that shows how to listen to the process output / log, collect the log, and conditionally exit: fork-listener.feature
Another answer which can be a useful reference: Conditional match based on OS
And here's how to use cURL for advanced HTTP tests ! https://stackoverflow.com/a/73230200/143475
In case you need to do a lot of local file manipulation, you can use the karate.toJavaFile() utility so you can convert a relative path or a "prefixed" path to an absolute path.
* def file = karate.toJavaFile('classpath:some/file.txt')
* def path = file.getPath()
I'm running a jar file from another jar like here somebody answers but waiting for the process.
Process proc = Runtime.getRuntime().exec("java -jar A.jar" + stringParams);
try {
proc.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
My problem comes when i have no feedback on the status of the program that is called, but i don't want my program continues beyond those lines. I would need the standard and error outputs but the results are shown when the execution is over. Is there any way of executing and getting those streams while the jar is still running?
Buffered/unbuffered
It seems like an issue with buffered output.
Executed process (in this case java -jar <path>) buffers output and writes it only when it's done (in big chunks, we don't like that!)
So one way to go is execute process through unbuffering (very hacky tools):
unbuffered <command>
stdbuf -i0 -o0 -e0 <command>
use terminal emulation
Hacking
stdbuf is part of GNU tools.
https://www.gnu.org/software/coreutils/manual/html_node/stdbuf-invocation.html
unbuffered is part of expect package.
https://wiki.tcl.tk/3548
The key thing is making the program thinking that it's in interactive mode (like you are launching it from console).
The first two options are very hacky and do not work in all cases (idk if java command works with them?)
Emulation
The third option is most promising.
We launch a program (terminal emulator) that emulates interactive terminal making program think it's working in real active session!
Pty4j
You might use pty4j too:
From there: https://github.com/traff/pty4j
// The command to run in a PTY...
String[] cmd = { "java", "-jar", "path_to_jar" };
// The initial environment to pass to the PTY child process...
String[] env = { "TERM=xterm" };
PtyProcess pty = PtyProcess.exec(cmd, env);
OutputStream os = pty.getOutputStream();
InputStream is = pty.getInputStream();
// ... work with the streams ...
// wait until the PTY child process terminates...
int result = pty.waitFor();
// free up resources.
pty.close();
Zt-exec
Maybe it's worth trying zt-exec?
I have no idea how it executes commands.
But it may be it (I didn't test that).
Using https://github.com/zeroturnaround/zt-exec
new ProcessExecutor().command("java", "-jar path_to_jar")
.redirectOutput(new LogOutputStream() {
#Override
protected void processLine(String line) {
...
}
})
.execute();
That should work, but I didn't test that.
In general, there are no ways to nicely resolve your problem.
Depending on what platforms you want to target consider using unbuffered, stdbuff or the (slowest) terminal emulation...
Please let me know if that helps and good luck! :)
I am calling a jar via perl with the following command.
my $command = "$java_home/bin/java my_jar.jar ARG1 ARG2 ARG3";
my $result = `$command 2>&1;
However my JAR also expects arguments via STDIN. I need to know how to pass those arguments. I have tried passing them like normal arguments, and that didn't work. I read on a forum that OPEN2 might work however after reading the documentation I couldn't figure out how to make it work.
Any ideas on how to make this work would be great.
Thanks ahead of time.
Since you need to send and receive data from the Java process, you need two-way communication. That's what IPC::Open2 is designed to do. This allows you to create a dedicated pipe that renders STDIN/STDOUT unnecessary:
use IPC::Open2;
my $pid = open2( \*from_jar, \*to_jar, $command )
or die "Could not open 2-way pipe: $!";
print to_jar, "Here is input\n"; # Pass in data
my $result = <from_jar>; # Retrieve results
Also consider IPC::Open3 to handle errors as well.
I used system("java .....")to run a java app in cmd with VC++ code.
The java app will run a server in the cmd,it will output info in the console.And I can also enter commands to it just like run "dir" commands in cmd.
Now I want get all the output in my program and use C++ code to write commands sent to the java app.
But I found that the system() won't return until I stop the java app.It's reasonable.And how to avoid it?Use Thread ?
And the biggest problem is I don't know how to get the output and write commands,can anyone give me a method?
Thanks a lot!
P.S. The java app's code can't be changed.
--------------------------------------I have made progress--------------------
int main()
{
char psBuffer[256];
FILE* output = _popen("java xxxx.jar", "rt" );
if(output == NULL)
return 0;
while(fgets(psBuffer, 256, output))
{
printf(psBuffer);
}
if (feof( output))
{
printf( "\nProcess returned %d\n", _pclose( output ) );
}
else
{
printf( "Error: Failed to read the pipe to the end.\n");
}
system("pause");
return 0;
}
When I use "dir".It works perfect!But when I use java,psBuffer is always nothing,and the output of java app is normally.Is it pipe cannot redirect java's output?
I change my code and make some java command run perfect:
FILE* output = _popen("java -version 2>&1", "rt" );
But when it run that .jar,It failed.I read the .jar's code and find the output is create by java.util.logging.Logger.info().I'm not familiar with java. How dose the info() work in cmd?
Thanks many!
Finally, I found last code above is work correctly.But origin output of java app haven't been redirect .It will display normally,but buffer is correctly received the output I want.Anyway I solved my problems.Thanks everyone!!!
The MSDN article Creating a Child Process with Redirected Input and Output explains how you can do it. It is quite a lot of code to go through, but will allow you to do what you want, and give you full control over it.
On the other hand, using _popen is much easier, but you don't have as much control. Depends on your exact needs as to how much code you'll be writing :).
I'm writing a wrapper script using Groovy (but the question is really a Java one) and would like to know if it's possible to create a Process without letting it run first. The problem is that the Process starts running and generating output on stdout and stderr. I would like to forward those to their appropriate destinations and at the same time create a merged stream for processing within the script. The problem I'm running into, however, is that the Process generates output too quickly and the output on the first two lines is a bit garbled. I would like to setup the streams before the process starts running. Any way to do that?
This consumes the output and error streams into two separate StringWriters, but I don't see anything "garbled"
new StringWriter().with { out ->
new StringWriter().with { err ->
'ls /tmp'.execute().with { proc ->
consumeProcessOutput( out, err )
waitFor()
}
println "OUT: $out"
println "ERR: $err"
}
}