I'm writing a Java program that reads a file from stdin and then prompts the user for interactive input. It should be executed like:
cat file.txt | java -jar myprog.jar
#
# ...Read file.txt then prompt user:
#
Some input please:
The problem is that after reading file.txt, the stdin seems "used up" and I don't know how to restore it to get user's input. Here's an example of what I'm trying to do:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
String line;
while((line = br.readLine()) != null) {
// Do something with line
System.out.println(line);
}
br.close();
Scanner scanner = new Scanner(System.in);
String input= scanner.nextLine();
}
}
When I executed it, I get:
echo -e "foo\nbar\nbaz" | java -jar biojava-tmp.jar
foo
bar
baz
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
at biojava_tmp.Main.main(Main.java:21)
How can I resolve this?
PS: In my real program I don't use Scanner, instead I use jline as below but I figure the problem is the same.
ConsoleReader console= new ConsoleReader();
console.readLine()
Related
I am trying to view the temperature table for my CPU on my Linux machine with Java. This bit of code will display the shell output for other commands, ls, cat file, but will not display watch sensors as it returns an interactive output. Is there a way I can convert it to plain text somehow?
Error: [/usr/bin/watch, sensors]
Error opening terminal: unknown.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class tempapp{
public static void main (String args[]) throws IOException, InterruptedException {
//build command
List<String> commands = new ArrayList<String>();
commands.add("/usr/bin/watch");
//args
commands.add("sensors");
System.out.println(commands);
ProcessBuilder pb = new ProcessBuilder(commands);
pb.directory(new File("/home/ethano"));
pb.redirectErrorStream(true);
Process process = pb.start();
//Read output
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null, previous = null;
while ((line = br.readLine()) != null)
if (!line.equals(previous)) {
previous = line;
out.append(line).append('\n');
System.out.println(line);
}
//Check result
if (process.waitFor() == 0){
System.out.println("\n success");
System.exit(0);
}
//weird termination
System.err.println(commands);
System.err.println(out.toString());
System.exit(1);
}
}
All that watch does is call the command it is given (sensors in this case) once every two seconds. You can simply have your application emulate this behaviour by calling /usr/bin/sensors in a for-loop once every two seconds (or however many times you need), therefore omitting the need to read interactive shell output.
sorry when I tag ffmpeg because I couldn't tag MP4Box.But I have proplem with excuted with ffmpeg via javacode too.
I read at How to execute cmd commands via Java but i can't find my proplem.
I'm tested commands in cmd, it was ok:
MP4Box -dash 10000 -dash-profile live -segment-name output- seg -rap
-bs-switching no input.mp4
but when i executed cmd via java code , i get error:
Error - only one input file found as argument, please check usage
Below is my code, has something wrong?
package com.uit.reformatvideo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Logger;
public class ExecuteComandToFormatVideo {
public final static String LINK_MP4BOX = "C:/MP4Box/Tools/MP4Box.exe";
public final static String CREATE_MPD_ECLIPSE = "mp4box -dash 10000 -frag 1000 -rap -bs-switching no";
public final static String CREATE_MPD_IE = "MP4Box -dash 10000 -dash-profile live -segment-name output-seg -rap -bs-switching no";
private static final Logger log = Logger.getLogger(ExecuteComandToFormatVideo.class.getName());
public static void main(String[] args) throws IOException, InterruptedException {
String s = null;
try {
// run the Unix "ps -ef" command
// using the Runtime exec method:
String lsCmd[] = new String [2];
lsCmd[0] = LINK_MP4BOX;
lsCmd[1] = "MP4Box -dash 10000 -dash-profile live -segment-name output-seg -rap -bs-switching no input.mp4";
Process p = Runtime.getRuntime().exec(lsCmd);
p.waitFor();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
System.exit(-1);
}
}
}
Here was out put:
Here is the standard output of the command:
Here is the standarderror of the command (if any): Error - only one
input file found as argument, please check usage
sorry because my English is bad. I created a bat file which included command such as CMD, then I used Runtime.getRuntime().exec(url+name+".bat");
to execute the bat file. This is my solution.
My bat file:
cd C:/MP4Box/Tools/
MP4Box
MP4Box -dash 10000 -dash-profile live -segment-name output-seg -rap -bs-switching no "C:\Users\ducth\Desktop\New folder (2)\SharingVideo\src\main\webapp\resources\video\output.mp4"
This question already has answers here:
Start CMD by using ProcessBuilder
(3 answers)
Closed 9 years ago.
I would like to know if its possible to run cmd through Java. Not just one command at a time but a continuous stream of user input commands that relays the info received. Is this possible or should I just stop trying now?
I'm not sure why I'm attaching this; it's not very relevant, but this is what I was trying to accomplish this with. However, it resets the cmd after every command. (Yes, I realize this is bad coding, but I'm just attempting something my boss asked about.)
import java.io.*;
import java.util.Scanner;
public class Cmd {
public static void main(String[] args) throws IOException {
String line;
while (true) {
Scanner scanner = new Scanner(System.in);
String comm = scanner.nextLine();
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", comm);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (true) {
line = r.readLine();
if(line==null){break;}
System.out.println(line);
}
}
}
}
Basically, cmd but behind a Java GUI with user input commands is my end game. If anyone could tell me if this is possible and if so point me in the right direction I would be grateful.
Yes, it is possible.
At the end of my answer is an example program. It is far from perfect and is missing some implementation details. For example proper exception handling and also detect when the cmd has exited... But it may be used as a starting point.
In essence the solution to your question is to start cmd.exe as a new Process. Then read commands in java from standard input stream (System.in) and pipe it to the cmd.exe-process. To provide feedback to the user you must read the standard output from cmd.exe-process and print it to the standard output of your java process (System.out). Also read standard error from cmd.exe-process and print it to standard error of your java process (System.err).
Close all resources when you are done. I indicated this in the example, but this is not production ready. Any exception would prevent the example program from cleaning up.
Another implementation detail: The example program uses a second thread to read output from cmd.exe-process. Otherwise you will only get output when the user hits enter.
Finally, here is the code:
package com.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class JavaCmd {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
ProcessBuilder procBuilder = new ProcessBuilder("cmd.exe");
Process proc = procBuilder.start();
PrintWriter outToProc = new PrintWriter(proc.getOutputStream());
final BufferedReader inFromProc = new BufferedReader(new InputStreamReader(proc.getInputStream()));
final BufferedReader errorFromProc = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Thread outputThread = new Thread(new Runnable(){
#Override
public void run() {
while(true) {
try {
while(inFromProc.ready()) {
String line = inFromProc.readLine();
System.out.println(line);
}
while(errorFromProc.ready()) {
String line = errorFromProc.readLine();
System.err.println(line);
}
} catch (IOException e) {
throw new RuntimeException("Error in output thread", e);
}
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println("Output Thread interrupted -> Thread will terminate");
break;
}
}
}
});
outputThread.start();
System.out.println("\n\nProxy shell is ready. Enter 'quit' to leave program.\n\n");
System.out.flush();
String line = null;
while((line = reader.readLine()) != null) {
if(line.equalsIgnoreCase("quit")) {
System.out.println("Good Bye");
break;
}
outToProc.println(line);
outToProc.flush();
}
reader.close();
outputThread.interrupt();
proc.destroy();
}
}
Hi i am trying to run shell script from following code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ScriptTest {
public static void main(String[] args){
BufferedReader stdErr=null;
BufferedReader stdIn=null;
try{
System.out.println("In Script");
String[] commands= {"ls"};
Process process = Runtime.getRuntime().exec("/mobilityapps/testScript/testScript.sh");
stdIn= new BufferedReader(new InputStreamReader(process.getInputStream()));
stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String inline= stdIn.readLine();
String errline =stdErr.readLine();
System.out.println("*Inline*"+inline);
System.out.println("*Errline*"+errline);
while(inline!=null){
System.out.println(inline);
inline=stdIn.readLine();
}
while(errline!=null){
System.out.println(errline);
errline=stdErr.readLine();
}
System.out.println("Process Exit Value: "+process.waitFor());
}catch(Exception excp){
excp.printStackTrace();
}
}
}
The script i am trying to call is
CURRDATE=`date '+%d%b%Y'`
TIMESTAMP=`date '+%H:%M'`
BASE_PATH=/mobilityapps/testScript
LOGFILE=${BASE_PATH}/logs_${CURRDATE}_${TIMESTAMP}.log
echo ${CURRDATE} ${TIMESTAMP}>>${LOGFILE}
All both the script and Java program are in the same directory.
When i run testScript.sh from PUTTY it runs fine
But when i run from Java program Process Exit Value is 255
Can anyone suggest the changes?
Try replacing the path
Runtime.getRuntime().exec("/mobilityapps/testScript/testScript.sh");
with
Runtime.getRuntime().exec("./mobilityapps/testScript/testScript.sh");
If you just use / at the begining, it means that it's a absolute path.
Using '.' indicates that is a relative path.
I need to execute the less command, with paging, from my Java console application. However, the only method I found to execute external commands is Runtime.getRuntime().exec(), which requires me to write/read input/output via streams. So commands like cat work (and less does in fact act like cat), but I need the paging functionality.
In C, I'd use system(). In Ruby, Kernel.exec does the job.
Is there any way to get this done in Java?
When you execute an external process with Runtime.exec() its standard input and output streams are not connected to the terminal from which you are running the Java program. You can use shell redirection to connect it, but first you need to know what terminal to use. There is no way to find the terminal using the standard API but probably you can find an open source library that does it.
To see that it can be done, this program opens itself in less:
public class Test {
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec(
new String[] {"sh", "-c",
"less Test.java < "+args[0] + " > "+args[0]});
System.out.println("=> "+p.waitFor());
}
}
To run it you should use java Test $(tty). The tty program prints the name of the terminal connected to its stdin.
I'm not too sure about the portability of this solution; at least it works on Linux.
List item
The following program will work, initially it prints 10 lines , then press enter it will print next line till end of the file.
run program like
java Less $fileName
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
public class Less
{
public static void main(String args[]) throws IOException
{
FileReader reader = new FileReader(args[0]);
BufferedReader buff = new BufferedReader(reader);
String readLine;
int lineCount = 0;
while ((readLine = buff.readLine()) != null)
{
System.out.println(readLine);
lineCount++;
if (lineCount > 10)
{
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
}
}
}
}