Java command line angle brackets - java

How do you read from and write to files passed on the command line using the < and > symbols?
This is the command: java Main < input.txt > output.txt
So I want to know what the code in the java file will look like. How do I reference these files?
Just to clarify, I can use files no problem if passed with: java Main input.txt output.txt
but I'm currently constrained to using the angle brackets.

Assuming that you are talking about Linux/Unix/Bsd ...
The < and > redirections are handled by the shell itself. By the time your Java application is called, the shell has already figured out what the pathnames resolve to, opened them, and connected them to the file descriptors used for System.in and System.out.
So you just code your program to read from System.in and write to System.out.
(The same principle applies if your application is part of a pipeline, and if FD #2 is redirected, that will be connected to System.err. The only thing that is not straightforward is if you do something unusual like this:
java Main < input.txt 3> output.txt
That will redirect FD #3 to a file. AFAIK, there is no simple way to write to FD's beyond 2 from Java.)

These operators mean that you want to read the input from input.txt and write the result to output.txt.

Following normal conventions, < is System.in and > is System.out. However, passing just a String to System.in probably does not do what you expect it to in this case

Related

java reads "*" in args[0] as the .class file

I want some code in my program to run only if the user has input the character '*' at the command-line as a command-line argument. This is the code I've used:-
//myfile.java
import java.io.*;
public class myfile {
public static void main(String[] args) {
if(args[0].equals("*")){
//do stuff
System.out.println(args[0]);//added this line to see what exactly was being passed
}
}
}
When this program is executed at the command-line by entering:-
java myfile *
the output I'm expecting to see on the screen is the asterisk character, instead the output displayed is 'myfile.class'. Where am I going wrong? Why does Java change the asterisk to the .class file?
Also, note that the program worked perfectly the first four times I executed it and then started doing this!
Thanks in advance for your help.
Where am I going wrong?
The star character needs to be quoted or escaped. Run your java program like this:
java myfile "*"
or
java myfile \*
Why does Java change the asterisk to the .class file?
It doesn't. It is your shell that is doing it. It is shell file expansion ... or "globbing" as it is also called.
Run "ls *" or "echo *" and you will see that the same thing happens.
The command terminal already replaces the asterisk and java already gets the value that you see. I'd use any other character, that has no special meaning to the command terminal or otherwise you must escape the asterisk in your command.
Actually escaping arguments on Windows and especially in cmd.exe is non-trivial. This nice article explains it in detail: Everyone quotes command line arguments the wrong way :
the takaway for your case is: surround the asterisk with quotes.
Answer to your question in the comment:
Using the escape character worked! But I still don't get why it worked without the escape character the first few times
I am not sure, but maybe you run into this behavior: It makes a difference if the pattern can be expanded or not. For example, when I pass Test* as argument, then there are 2 cases to consider:
in the current folder there is a file called Test1.txt: then your java program will get Test1.txt as argument
when there are no matching files, your program will get Test* as argument
However, I am not sure, how this would apply to your case, since you only pass *: that should only work in an empty directory.

Java Runtime.getRuntime().exec(cmd) command contain single quote

I need to use Java to rsync several files using one command
the following command works fine in shell
rsync -avrz --timeout=100 rsync://10.149.21.211:8730/'logflow/click/file1 logflow/click/file2' /home/kerrycai/puller"
but when i use the following Java code , it does not work
String cmd = "rsync -avrz --timeout=100 rsync://10.149.21.211:8730/'logflow/click/file1 logflow/click/file2' /home/kerrycai/puller";
Process p = Runtime.getRuntime().exec(cmd);
int ret = p.waitFor();
the ret value is not equal to 0 (5 in my test), and the command is not executed succeed, after some debugging , it seem the problem is caused by the single quote
So, my questions is
Can I using java to execute a shell command which has single quote in it (Pls note, the single quote is in the middle of a parameter, not start/end) ?
Can I have a shell command to rsync several files in one command , and the command does not have single(double) quotes in it ?
Note to #Chris: this combination of multiple filenames (really modified-partly-like-filenames) in one argument is indeed very unusual and even 'suspicious' for Unix in general, but is (or at least was) correct for rsync in particular.
Preface: Java Runtime.exec does NOT 'execute a shell command' (unless you explicitly run a shell and give it a command); it runs a program, with arguments. These different things are often confused because most of the shell commands used by normal users are commands to run programs, but this is one case where the difference matters. In particular quoting a space to shell causes the shell to pass a single argument to the program containing the space instead of splitting into two (or more) arguments, but the quote itself is NOT included in the argument.
First you should look at the man page (on your system or online at https://download.samba.org/pub/rsync/rsync.html) under ADVANCED USAGE. Current (and IME even moderately old) versions of rsync have a more convenient syntax with separate arguments to get multiple files, which the simple parsing used by Runtime.exec(String) can handle like this:
rsync -avrz --timeout=100 --port=8730 10.149.21.211::logflow/click/file1 ::logflow/click/file2 /home/kerrycai/puller
But if you need (or really want) to use the quoted-space form then you need to do the tokenization yourself and use the String[] overload as suggested by #EJP -- although you can still use Runtime, you don't need ProcessBuilder for this. Specifically do something along the lines of:
String[] cmdarray = {"rsync",
"-avrz",
"--timeout=100",
"rsync://10.149.21.211:8730/logflow/click/file1 logfile/click/file2",
// separated argument contains space but not single (or other) quote
"/home/kerrycai/puller" };
... Runtime.getRuntime.exec(cmdarray); ...
You're calling a somewhat large command from Java. Why not just use a shell script? Put your gnarly command in myScript.sh and then have Java invoke /bin/bash myScript.sh. Makes all the weirdness to do with string handling in Java go away.

Concise way of capturing the output of process in Java

To capture the output of process in Groovy I use the following:
"command".execute().text
I want to do the same in Java, but all responses I found contain a lot of boilerplate code involving loops, BufferedReader, Scanner, etc.:
Get Command Prompt Output to String In Java
How to run Windows commands in JAVA and return the result text as a string
java runtime.getruntime() getting output from executing a command line program
Can I do the same thing within 1-2 lines of code? Maybe Guava or Apache have something to make life simpler?
I've managed to come up with the following two-liner:
Process process = Runtime.getRuntime().exec("command")'
String output = IOUtils.toString(process.getInputStream());

Bash input redirection with newlines

So for an assignment at school I am required to make a program in java that manages some students at a college, the user may invoke a number of function, but I started by testing 'add'.
My prof recommends that I use input redirection, because I can easily test the program over and over, without much typing. Now here is the issue.
echo `< input.txt`
add Student Name 123 Street,City,Province,Postal Code q
#Input rediraction ate my newlines
cat input.txt
add
Student Name
Street,City,Province,Postal Code
q
#What I actually want to run
java -cp . TestCollege < input.txt #fail horribly
As you can see bash removes the newline characters I use to delimit my input, and thus my program crashes, because when you run it in interactive mode, Scanner.getLine() just blocks until input occurs.
Any idea how I can give my program the input with the newlines, it seems to work fine in windows "cmd" but not in "bash".
Could you try wrapping BufferedInputStream around System.in, because it can handle both cases: \r\n and \n; and I think that's where your problem lies.
Or rather, call useDelimiter(System.getProperty("line.separator")) on Scanner.
Well, you can see how bash does not eat the newlines running
$ wc -l < input.txt
Which I guess will give you the value you'd expect.

Error when using Runtime.getRuntime().exec method to invoke an exe, if exe path has non-english chars

I am using Runtime.getRuntime.exec() Method to invoke an exe. The problem what I face with this method is that when I pass some exe path (c:\JPN_char_folder\mypath\myexe.exe) with other language chars (ex.Japanese) "it's saying "System cannot find the file specified". Would you please suggest some ideas to get around this? I even tried passing that exe path after converting to UTF-8 as well, but still I could not solve this.
-Robert.
I don't think that Japanese characters are the issue; it's the c: drive.
You need to write it this way:
String path = "c:\\\JPN_char_folder\\mypath\\myexe.exe";
See if that helps.
Most probably you have an encoding problem somewhere.
There are several steps here that the path value takes:
InstallAnywhere retrieves the path
InstallAnywhere puts it into a variable
Java reads the variable
Java puts it into a String
Java creates a java.io.File instance from String
Java runtime passes path (via File) to OS
Somehwere along this sequence something goes wrong with the path :-(.
It's hard to tell where; your best bet probably is to try and print out the value at every step along the path, to see where it goes wrong.
At least from inside Java, you should probably print out the String both as text, and as a list of Unicode code points (using String.codePointAt). That way you can see the real data Java uses.
Another approach:
Print out the value Java gets from InstallAnywhere (as text & as codepoints, as above)
Try to put the path into your Java program as a String literal, and fiddle until you can open the file that way. Then print that String as well.
Now you can compare the two results; that should give you an idea where the path gets messed up.
Note:
Does the path contain characters outside the Basic Multilingual Plane (BMP)? Java handles these a bit awkwardly, so you need to pay extra attention. Maybe you can check this first.
Even if you're using Windows, you can use slashes when specifying directories. This will help you with escaping backslash hell.
For example, on my system, 7z is located in directory c:\Program Files\7-Zip\.
Executing this
File file = new File("c:/Program Files/7-Zip/7z.exe");
if(file.exists()) {
System.out.println(file.getAbsolutePath());
}
Results in
c:\Program Files\7-Zip\7z.exe
being printed on the console.
I'd suggest you try using this idiom, i.e. check if .exe file exits before trying to execute it.

Categories