Want to get standard output or error when using Process - java

I want to use "which hoge" for obtaining a path for the hoge in Java code.
when "hoge" exists, the path can be obtained by Process#getInputStream.
but when "hoge" doesn't exist, both input stream and error stream from Process#get(Input|Error)Streams give "null".
but in terminal (OS X), if I try "which unexists", I get "unexists not found".
where does the message "unexists not found" go? How can I get this?
Does Java use another "which"?

Your shell probably has "which" as a built-in command, so it doesn't use the /bin/which program. There are likely many differences between the two. You can check which which you use with the command "type which" and use the program instead of the built-in command using /bin/which.
From Java, you can know if a result was found by checking the process exit status returned by Process.waitFor(). If the status is 0 which found a match, if non-zero it didn't or there was some other error.

Related

how can we simulate Ctrl+C to stop the console app from waiting for user input in java

I am trying to test a command line app that waits for the user input after every step. I am able to test the app using System Rules provided by Stefan Birkner. Currently, I provide inputs from the beginning to the end which works like a charm and I can assert the final output from system log.
However, I want to test for the negative cases before the end of the app for which I give invalid inputs in the beginning to evaluate the error message. When invalid inputs are given, the console prints an error message and keeps waiting for the user to provide a valid input. How do I send Ctrl+C using as shown below:
systemInMock.provideLines(Ctrl+C);
systemInMock.provideLines accepts only strings. Is there a way to send Ctrl+C signal?
An example of my junit test is shown below:
#Test
public void testInValidMarker() throws Exception{
systemInMock.provideLines("abc","def","1");
Main.main(new String[]{});
assertTrue(systemOutRule.getLog().contains("Invalid marker, try again"));
}
Appreciate your help!
If I'm not mistaken, when you do ctrl+c, it doesn't actually get written to console. If that's true, then in no case will your program ever be given ctrl+c, so provideLines will never be in a position where it is given ctrl+c.
For proof, open up cmd and type in a program with program arguments (in my case, I use ant). If you type ant and then ctrl+c, the cursor is moved to a new line.
There are two ways you can control termination behavior:
You can use a shutdown hook (found from this previously asked question ). Doing this will allow you to handle what happens (potentially with issues).
Or you could create your own termination argument like -q or q, which would trigger an action to end the program (maybe a System.exit(1)). This way you can mock that input.
In UNIX/Linux, when you type CTRL-C, your shell intercepts it and sends the process a SIGINT signal -- see: How does Ctrl-C terminate a child process?
Therefore the System Rules project doesn't have anything to help you -- in this situation the process doesn't receive any character input.
By default, the whole JVM shuts down when it receives SIGINT. This is obviously bad news for a running test.
The SO question Signal handling using "TERM" -- may be of use.
A side effect of Java's portability is that for some OS features, it either abstracts things away until they're unrecognisable, or doesn't expose them at all.
I suspect what you're asking for can't be achieved.
If you're allowed to change the requirements slightly, you could ask the user to close with CTRL-D -- this closes stdin with EOF.
Although it's quite the overkill, you could launch a whole new JVM running your program, using ProcessBuilder. You might imagine you'd get an API to send arbitrary signals to that process. But for portability reasons, all you can do is process.destroy(), which sends SIGTERM.
Tried this as a comment, but it didn't read right. It's not exactly an "Answer" though.
So Java is really bad at console input. It reads an entire line at once and you can't do anything about it--there is no way to trap special characters or even see any of the input before the user hits return. Also I think a ctrl-d will close your input session--(Add that test to your use case if you don't use any other suggestion here because it can put you into a state you didn't expect!)
Three suggestions:
The simplest: If you can use a GUI and aren't really looking for an ongoing input/response REPL the simplest answer is usually to use JOptionPane to throw up a quick dialog. It's a one-line solution to get some user input, but not so good for an ongoing command-driven system.
If you can't use swing (If you are running headless) then you may have little choice, but you can use the JLine library. That will give you a lot more flexibility. This is how Groovysh does it's REPL. It will let you see each character as it is typed and do things like completion where a user might type part of a file name and hit tab and you put the rest in for him.
If you don't want to use JLine but want a REPL feel there is also a more complex GUI solution--create a swing console window. A trivial solution would just be a text input box to allow typing and a text area to display results, but there are certainly libraries out there with more complete console solutions.
The point here is that using Java standard input alone is just not a good solution for anything beyond a trivial/personal script--and even then I avoid it. Perhaps not the answer you asked for, but maybe it's the one you need :)

How do I find which class is printing an error?

I have a Java program, using Vertx 2, and when I run it, I get a message:
% vertx run -cluster com.abc.prep.manager.PrepStartup -cp ./build/libs/Operational-all-1.0.jar -conf safe.conf
Starting clustering...
No cluster-host specified so using address 172.17.0.1
[Fatal Error] :6:3: The element type "hr" must be terminated by the matching end-tag "</hr>".
Prep Starting up!
Succeeded in deploying verticle
I cannot figure out where that '[Fatal Error]' message is coming from. If someone knows what vertx is doing (since I think it's coming from there), that would be great.
But my real question is: How do I find out who is printing that? What class in which jar? I can't seem to set a breakpoint in System.out or System.err that catches it (I'm using Intellij). Can I override (all) output so that it prints a stacktrace?
How do you find who is printing that? I can't speak to specifics with Vertx 2, but I've had to track down plenty of mysterious errors. This is my general pattern, applied as far as possible to yours:
Get an idea of what the error is. Google the static (would be the same for anybody) elements in the error message. Here, that could be "must be terminated by the matching end-tag". Adding "vertx" to the query gave me some links, but I didn't see any instant answers. I did find out that it's probably an XMLStreamException. You might be able to breakpoint on that.
Assuming that didn't work, search your code base by text, looking for that same static text. Armed with the knowledge from your Google investigation, you should be able to narrow down any results to a manageable number to check.
If your search finds nothing, make sure you have source files attached for everything in your module that you can get source files for. Then retry step 2.
Once you've found the code that throws the error, you should be able to put a breakpoint.

Bash script -- Using expect to read from Standard Output

I have a java program that is known to be functional. I am trying wrap a bash script around it to pass in each index in the associative array as a parameter. When the java program is run, Maven writes output to the console.
What I want is for bash to wait to see the line "[INFO] BUILD SUCCESS" in the standard output before moving on. Once it has that confirmation that the java process ran successfully, I perform some tasks on the text file the java program created. Only then do I want to go to the next iteration of the loop.
I have an associative array of parameters:
params=([1]cat [2]dog [3]fish)
Loop logic:
for i in "${!params[#]}"
do
mvn exec:java -Dexec.mainClass="com.company.ProgramMainClass" -Dexec.args="$i '2015-11-01'" | /usr/bin/expect "[INFO] BUILD SUCCESS"
mv /tmp/outputfile.csv /path/to/directory/${params[$i]}_outputfile.csv
done
I cannot figure out the syntax to make expect work on standard output. I've read several examples and pawed through the expect manual, but I'm just not understanding how it works.
I feel like I should be able to pipe standard output to expect and have the script wait until expect sees the given string. But it's not working. Any advise? Thanks.
If you want you can use expect like this:
#!/usr/bin/expect
set timeout -1
expect "*\\\[INFO\\\] BUILD SUCCESS*"
The triple backslashes are needed for square bracket protection in Tcl.

What determines where a System.out.println(args) command prints to?

It may be a silly question but I can't find anything on the web with the answer. What (if anything) determines where the args of a System.out.println(args) command will be displayed? I've been using an IO class created by my lecturer which created it's own GUI and wrote to specific areas of that by default but now that I am making my own programs I am struggling to get the text/images/whatever to display where I want it to.
From the Javadocs for System.out:
The "standard" output stream. This stream is already open and ready to accept output data. Typically this stream corresponds to display output or another output destination specified by the host environment or user.
In most computing environments, there are three standard streams associated with a process.
Note, however, that System.out can be reassigned in Java, by using System.setOut().
Depending on the operating system you're using, each process has associated a standard input, standard output and a standard error. If you execute your program in a console, the it will be your standard input, output and error.
For instance, in Linux you can redirect the standard output with redirection operators like this:
java MyClass > fileAsOutput.txt

How do you get a process id in java?

I am trying to find a way to programmaticaly open and close an application. I can launch the application easily using
Runtime.getRuntime().exec(new String[] {"open", "<path to application>"});
however, the only way I can find to close it is to use the line
Runtime.getRuntime().exec(new String[] {"kill", "<process id#>"});
and I can't find anyway to get the id # other than manually opening terminal and using top to find the #. If there is a programmatic way to get this id, or just a better way to go about opening and closing applications i would love to hear about it.
Thanks
Use a java.lang.ProcessBuilder to start the subprocess. The returned Process object has a destroy() method which will let you kill it.
This probably isn't relevant anymore to the original poster (due to the elapsed time) but just for the sake of completeness...
You get a handle to the process object as a result of the exec(...) command:
Process myProcess = Runtime.getRuntime().exec("mybin");
You can then kill at any later time with destroy():
myProcess.destroy();
Note: This might be similar to what Jim was describing but not using the ProcessBuilder.

Categories