Split a string containing command-line parameters into a String[] in Java - java

Similar to this thread for C#, I need to split a string containing the command line arguments to my program so I can allow users to easily run multiple commands. For example, I might have the following string:
-p /path -d "here's my description" --verbose other args
Given the above, Java would normally pass the following in to main:
Array[0] = -p
Array[1] = /path
Array[2] = -d
Array[3] = here's my description
Array[4] = --verbose
Array[5] = other
Array[6] = args
I don't need to worry about any shell expansion, but it must be smart enough to handle single and double quotes and any escapes that may be present within the string. Does anybody know of a way to parse the string as the shell would under these conditions?
NOTE: I do NOT need to do command line parsing, I'm already using joptsimple to do that. Rather, I want to make my program easily scriptable. For example, I want the user to be able to place within a single file a set of commands that each of which would be valid on the command line. For example, they might type the following into a file:
--addUser admin --password Admin --roles administrator,editor,reviewer,auditor
--addUser editor --password Editor --roles editor
--addUser reviewer --password Reviewer --roles reviewer
--addUser auditor --password Auditor --roles auditor
Then the user would run my admin tool as follows:
adminTool --script /path/to/above/file
main() will then find the --script option and iterate over the different lines in the file, splitting each line into an array that I would then fire back at a joptsimple instance which would then be passed into my application driver.
joptsimple comes with a Parser that has a parse method, but it only supports a String array. Similarly, the GetOpt constructors also require a String[] -- hence the need for a parser.

Here is a pretty easy alternative for splitting a text line from a file into an argument vector so that you can feed it into your options parser:
This is the solution:
public static void main(String[] args) {
String myArgs[] = Commandline.translateCommandline("-a hello -b world -c \"Hello world\"");
for (String arg:myArgs)
System.out.println(arg);
}
The magic class Commandline is part of ant. So you either have to put ant on the classpath or just take the Commandline class as the used method is static.

If you need to support only UNIX-like OSes, there is an even better solution. Unlike Commandline from ant, ArgumentTokenizer from DrJava is more sh-like: it supports escapes!
Seriously, even something insane like sh -c 'echo "\"un'\''kno\"wn\$\$\$'\'' with \$\"\$\$. \"zzz\""' gets properly tokenized into [bash, -c, echo "\"un'kno\"wn\$\$\$' with \$\"\$\$. \"zzz\""] (By the way, when run, this command outputs "un'kno"wn$$$' with $"$$. "zzz").

You should use a fully featured modern object oriented Command Line Argument Parser I suggest my favorite Java Simple Argument Parser. And how to use JSAP, this is using Groovy as an example, but it is the same for straight Java. There is also args4j which is in some ways more modern than JSAP because it uses annotations, stay away from the apache.commons.cli stuff, it is old and busted and very procedural and un-Java-eques in its API. But I still fall back on JSAP because it is so easy to build your own custom argument handlers.
There are lots of default Parsers for URLs, Numbers, InetAddress, Color, Date, File, Class, and it is super easy to add your own.
For example here is a handler to map args to Enums:
import com.martiansoftware.jsap.ParseException;
import com.martiansoftware.jsap.PropertyStringParser;
/*
This is a StringParser implementation that maps a String to an Enum instance using Enum.valueOf()
*/
public class EnumStringParser extends PropertyStringParser
{
public Object parse(final String s) throws ParseException
{
try
{
final Class klass = Class.forName(super.getProperty("klass"));
return Enum.valueOf(klass, s.toUpperCase());
}
catch (ClassNotFoundException e)
{
throw new ParseException(super.getProperty("klass") + " could not be found on the classpath");
}
}
}
and I am not a fan of configuration programming via XML, but JSAP has a really nice way to declare options and settings outside your code, so your code isn't littered with hundreds of lines of setup that clutters and obscures the real functional code, see my link on how to use JSAP for an example, less code than any of the other libraries I have tried.
This is a direction solution to your problem as clarified in your update, the lines in your "script" file are still command lines. Read them in from the file line by line and call JSAP.parse(String);.
I use this technique to provide "command line" functionality to web apps all the time. One particular use was in a Massively Multiplayer Online Game with a Director/Flash front end that we enabled executing "commands" from the chat like and used JSAP on the back end to parse them and execute code based on what it parsed. Very much like what you are wanting to do, except you read the "commands" from a file instead of a socket. I would ditch joptsimple and just use JSAP, you will really get spoiled by its powerful extensibility.

/**
* [code borrowed from ant.jar]
* Crack a command line.
* #param toProcess the command line to process.
* #return the command line broken into strings.
* An empty or null toProcess parameter results in a zero sized array.
*/
public static String[] translateCommandline(String toProcess) {
if (toProcess == null || toProcess.length() == 0) {
//no command? no string
return new String[0];
}
// parse with a simple finite state machine
final int normal = 0;
final int inQuote = 1;
final int inDoubleQuote = 2;
int state = normal;
final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
final ArrayList<String> result = new ArrayList<String>();
final StringBuilder current = new StringBuilder();
boolean lastTokenHasBeenQuoted = false;
while (tok.hasMoreTokens()) {
String nextTok = tok.nextToken();
switch (state) {
case inQuote:
if ("\'".equals(nextTok)) {
lastTokenHasBeenQuoted = true;
state = normal;
} else {
current.append(nextTok);
}
break;
case inDoubleQuote:
if ("\"".equals(nextTok)) {
lastTokenHasBeenQuoted = true;
state = normal;
} else {
current.append(nextTok);
}
break;
default:
if ("\'".equals(nextTok)) {
state = inQuote;
} else if ("\"".equals(nextTok)) {
state = inDoubleQuote;
} else if (" ".equals(nextTok)) {
if (lastTokenHasBeenQuoted || current.length() != 0) {
result.add(current.toString());
current.setLength(0);
}
} else {
current.append(nextTok);
}
lastTokenHasBeenQuoted = false;
break;
}
}
if (lastTokenHasBeenQuoted || current.length() != 0) {
result.add(current.toString());
}
if (state == inQuote || state == inDoubleQuote) {
throw new RuntimeException("unbalanced quotes in " + toProcess);
}
return result.toArray(new String[result.size()]);
}

Expanding on Andreas_D's answer, instead of copying, use CommandLineUtils.translateCommandline(String toProcess) from the excellent Plexus Common Utilities library.

I use the Java Getopt port to do it.

Related

Is there a way to store code as variables in java?

In Java, is there a way to store, edit, convert, print, access, evaluate and compare blocks of code (possibly user entered), while also being able to execute them?
An example for where this would be useful is if someone codes an software that is designed to teach people how to code, where the user would input code to the system, and the program would check if the user developed code is
I'm looking for something like this:
CodeBlock line20And21 = `String x = "hello"; System.out.println(x);`; // stores a block of code
line20And21.replace("ln",""); //edits the block of code
System.out.println(line20And21.toString()); // converts/prints the block of code
CodeBlock usersCode = Scanner.nextCodeBlock(); // accesses block of code
if(! line20And21.wouldThrowError()); // evaluates block of code
if(line20And21.wouldDoTheSameThingAs(line18And19)) // compares blocks of code
line20And21.execute(); // executes the block of code
The code I would be using is of course much more complicated than just defining a String and printing it, but I'm sure the idea would be the same.
I really appriciate any help with this. Thanks!
Since Java 9, Java includes a shell to evaluate snippets, called JShell. JShell is programatically available via jdk.shell.
First you have to create an instance of the JShell via JShell js = JShell.create().
Evaluating a String as Java code (a so called code Snippet) is done via js.eval("System.out.println(/"Hello World/")");, which returns a list of SnippetEvents you can inspect to find out what effect the execution of the code snippet had.
Since the code is stored as a String, you can edit it as you would edit any String.
Here is an example of JShell taking user inputted code and storing/evaluating it, taken from the official java docs, where code is read as string from stdin and executed:
import java.io.ByteArrayInputStream;
import java.io.Console;
import java.util.List;
import jdk.jshell.*;
import jdk.jshell.Snippet.Status;
class ExampleJShell {
public static void main(String[] args) {
Console console = System.console();
try (JShell js = JShell.create()) {
do {
System.out.print("Enter some Java code: ");
String input = console.readLine();
if (input == null) {
break;
}
List<SnippetEvent> events = js.eval(input);
for (SnippetEvent e : events) {
StringBuilder sb = new StringBuilder();
if (e.causeSnippet == null) {
// We have a snippet creation event
switch (e.status) {
case VALID:
sb.append("Successful ");
break;
case RECOVERABLE_DEFINED:
sb.append("With unresolved references ");
break;
case RECOVERABLE_NOT_DEFINED:
sb.append("Possibly reparable, failed ");
break;
case REJECTED:
sb.append("Failed ");
break;
}
if (e.previousStatus == Status.NONEXISTENT) {
sb.append("addition");
} else {
sb.append("modification");
}
sb.append(" of ");
sb.append(e.snippet.source());
System.out.println(sb);
if (e.value != null) {
System.out.printf("Value is: %s\n", e.value);
}
System.out.flush();
}
}
} while (true);
}
System.out.println("\nGoodbye");
}
}
You can do things like this with BeanShell, a Java interpreter written in Java:
import bsh.Interpreter;
class Test {
public static void main(String[] args) throws Exception {
String code = "String x = \"hello\"; System.out.println(x);";
String newCode = code.replace("ln", "");
System.out.println("Here's the result of running: " +newCode);
Interpreter p = new Interpreter();
p.eval(newCode);
}
}
If compiled and built with the right dependencies, you can evaluate the snippet:
$ javac -cp bsh-2.0b4.jar:. Test.java && java -cp bsh-2.0b4.jar:. Test
Here's the result of running: String x = "hello"; System.out.print(x);
hello$
You can run the code and get its output or return values, or whether it throws an exception. Sandboxing and comparing the output of two snippets is up to you.
Mostly: No.
Java code goes through a compilation step, code needs to be in methods (which need to be in types), and the reasons for this take quite a while to explain. The compiler does not need to be there at runtime (and often isn't).
So, if you really want to do this:
Code has to be 'complete', including a package statement, a class declaration, a method, etc.
You need to ship the compiler with the app. For javac, that's tricky (GPL); you could ship ecj (eclipse's compiler) which is MIT licensed. It's quite a dep.
You can then 'store' code as strings.
ecj can then turn this into bytecode for you, but you'll have quite a time managing the classpath properly to make this code compile correctly.
You can then dynamically load this bytecode by using a classloader which has a learning curve of a few days all by itself.
In addition, looking at code without executing it to determine if it would throw an exception or not is literally impossible - this is called the halting problem. There exists proof that it is unsolvable. You can't go faster than light. You can't determine from arbitrary code written in a 'turing complete' language (and java is turing complete) if it halts or not (or in this case, if it throws or not).
Similar rules apply to 'would this do the same thing as'.

How do I get my code to loop then clear screen of the previous result in Java? [duplicate]

Can any body please tell me what code is used for clear screen in Java?
For example, in C++:
system("CLS");
What code is used in Java to clear the screen?
Since there are several answers here showing non-working code for Windows, here is a clarification:
Runtime.getRuntime().exec("cls");
This command does not work, for two reasons:
There is no executable named cls.exe or cls.com in a standard Windows installation that could be invoked via Runtime.exec, as the well-known command cls is builtin to Windows’ command line interpreter.
When launching a new process via Runtime.exec, the standard output gets redirected to a pipe which the initiating Java process can read. But when the output of the cls command gets redirected, it doesn’t clear the console.
To solve this problem, we have to invoke the command line interpreter (cmd) and tell it to execute a command (/c cls) which allows invoking builtin commands. Further we have to directly connect its output channel to the Java process’ output channel, which works starting with Java 7, using inheritIO():
import java.io.IOException;
public class CLS {
public static void main(String... arg) throws IOException, InterruptedException {
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
}
}
Now when the Java process is connected to a console, i.e. has been started from a command line without output redirection, it will clear the console.
You can use following code to clear command line console:
public static void clearScreen() {
System.out.print("\033[H\033[2J");
System.out.flush();
}
Caveats:
This will work on terminals that support ANSI escape codes
It will not work on Windows' CMD
It will not work in the IDE's terminal
For further reading visit this
This is how I would handle it. This method will work for the Windows OS case and the Linux/Unix OS case (which means it also works for Mac OS X).
public final static void clearConsole()
{
try
{
final String os = System.getProperty("os.name");
if (os.contains("Windows"))
{
Runtime.getRuntime().exec("cls");
}
else
{
Runtime.getRuntime().exec("clear");
}
}
catch (final Exception e)
{
// Handle any exceptions.
}
}
⚠️ Note that this method generally will not clear the console if you are running inside an IDE.
A way to get this can be print multiple end of lines ("\n") and simulate the clear screen. At the end clear, at most in the unix shell, not removes the previous content, only moves it up and if you make scroll down can see the previous content.
Here is a sample code:
for (int i = 0; i < 50; ++i) System.out.println();
Try the following :
System.out.print("\033\143");
This will work fine in Linux environment
Create a method in your class like this: [as #Holger said here.]
public static void clrscr(){
//Clears Screen in java
try {
if (System.getProperty("os.name").contains("Windows"))
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
else
Runtime.getRuntime().exec("clear");
} catch (IOException | InterruptedException ex) {}
}
This works for windows at least, I have not checked for Linux so far. If anyone checks it for Linux please let me know if it works (or not).
As an alternate method is to write this code in clrscr():
for(int i = 0; i < 80*300; i++) // Default Height of cmd is 300 and Default width is 80
System.out.print("\b"); // Prints a backspace
I will not recommend you to use this method.
If you want a more system independent way of doing this, you can use the JLine library and ConsoleReader.clearScreen(). Prudent checking of whether JLine and ANSI is supported in the current environment is probably worth doing too.
Something like the following code worked for me:
import jline.console.ConsoleReader;
public class JLineTest
{
public static void main(String... args)
throws Exception
{
ConsoleReader r = new ConsoleReader();
while (true)
{
r.println("Good morning");
r.flush();
String input = r.readLine("prompt>");
if ("clear".equals(input))
r.clearScreen();
else if ("exit".equals(input))
return;
else
System.out.println("You typed '" + input + "'.");
}
}
}
When running this, if you type 'clear' at the prompt it will clear the screen. Make sure you run it from a proper terminal/console and not in Eclipse.
Runtime.getRuntime().exec(cls) did NOT work on my XP laptop. This did -
for(int clear = 0; clear < 1000; clear++)
{
System.out.println("\b") ;
}
Hope this is useful
By combining all the given answers, this method should work on all environments:
public static void clearConsole() {
try {
if (System.getProperty("os.name").contains("Windows")) {
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
}
else {
System.out.print("\033\143");
}
} catch (IOException | InterruptedException ex) {}
}
Try this: only works on console, not in NetBeans integrated console.
public static void cls(){
try {
if (System.getProperty("os.name").contains("Windows"))
new ProcessBuilder("cmd", "/c",
"cls").inheritIO().start().waitFor();
else
Runtime.getRuntime().exec("clear");
} catch (IOException | InterruptedException ex) {}
}
This will work if you are doing this in Bluej or any other similar software.
System.out.print('\u000C');
You can use an emulation of cls with
for (int i = 0; i < 50; ++i) System.out.println();
You need to use control characters as backslash (\b) and carriage return (\r). It come disabled by default, but the Console view can interpret these controls.
Windows>Preferences and Run/Debug > Console and select Interpret ASCII control characteres to enabled it
After these configurations, you can manage your console with control characters like:
\t - tab.
\b - backspace (a step backward in the text or deletion of a single character).
\n - new line.
\r - carriage return. ()
\f - form feed.
More information at: https://www.eclipse.org/eclipse/news/4.14/platform.php
You need to use JNI.
First of all use create a .dll using visual studio, that call system("cls").
After that use JNI to use this DDL.
I found this article that is nice:
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=5170&lngWId=2

How to Use Command Line Arguments to Dictate Flow of Program?

I have scoured all of Google it seems and I cannot find anything regarding how to use command line arguments to tell the Java program which subsequent method to perform. I am trying to create a Java program with several different aspects of a student grading application.
The main program is a GUI form where the user can input grades for each student in a specific class. Along with this, I need a control program that accepts 3 command arguments. The first is a number to indicate the type of file to load (1. XML 2. JSON 3. TXT). The second is a letter to indicate the file material (C indicates Course data, S indicates Student data). The last argument is the name of the specific data file to upload, which will then be extracted and uploaded to a database to be used by the GUI program.
I have the rest of the program already coded except for the command arguments because I have absolutely no idea what I am doing. The command argument code is supposed to look something like this:
public class Load
{
//Define global variables
static String inputDataChoice;
static String inputTableChoice;
static String inputFileName;
public static void main(String[] arg)
{
if (userChose == arg[0], arg[3], arg[5])
{
//If user chose 1 (XML), S (Student), and xmltest.xml
//Go to ParseXMLStudentFile();
}
if (userChose == arg[1], arg[4], arg[6])
{
//If user chose 2 (JSON), C (Course), and jsontest.json
//Go to ParseJSONCourseFile();
}
if (userChose == arg[2], arg[3], arg[7])
{
//If user chose 3 (TXT), S (Student), and test.txt
//Go to ParseTXTStudentFile();
}
}
}
I know that the above code is bogus, but that is the general idea. How do I accept command arguments from the user and then use that input to decide which method is executed? Would this program use the console window to accept user input? Please help!
arg contains the parameters passed to the command line, i.e. if you call the prog with prog.jar XML S xmltest.xml:
String fileType = arg[0]; // == XML
String material = arg[1]; // == S
String fileName = arg[2]; // == xmltest.xml
if (fileType.equals("XML") && material.equals("S")) {
parseXMLStudentFile(fileName);
} else { // ...
}

Java building an API, how to do different file handling based on file name?

I've been tasked to build an API that handles files in java. It is the first time I build the API in java. So now I have two problems.
Problem number 1:
My question is, how to do different file handling based on file name?
There are two types of files and the name of the file is such 162211_abFile.txt and the other file is 33232_abcTextFile.txt so the question is how do I get my api to run a particular method based on it is .... _abFile or .... _abcTextFile.
Problem number 2:
I have a couple of methods in another class that I need to call how do I do it in the most efficient manner? After I read the file ie.
This is my try when i read the files.
try{
BufferedReader br = new BufferedReader(new FileReader ("162211_abFile.txt"));
String line = null;
I hope I have explained well and that you understood my problem.
Thanks in advance!
Edit nr 1:
The method signatures
public interface PaymentReceiver {
public void startPaymentBundle(String accountNumber, Date paymentDate, String currency);
public void payment(BigDecimal amount, String reference);
public void endPaymentBundle();
}
Regarding your first question, you can accomplish it using regular expressions.
If the files follow the format [numbers]_[filename].txt you can do the following:
Pattern p = Pattern.compile("\\d+_(\\w+)\\.txt");
Matcher m = p.matcher("33232_abcTextFile.txt");
if (m.matches()) {
if (m.group(1).equals("abFile")) {
// Do something
} else if (m.group(1).equals("abcTextFile")) {
// Do something else
} else {
// Unknown filename, handle it
}
} else {
// Unknown file format, handle it
}
The pattern, the string fed to Pattern.compile, here is going to match 1 or more digits, followed by an underscore, followed 1 or more characters, followed by .txt.
If there should be more file names to consider in the future, you can just to ad another else if clause that handles that file name.

args in '.bat' file contain some spaces, how could I get the args correctly?

Stat command in cmd:
start.bat -arg1 -ar g2 -arg3
How can I get the second arg? The string 'ar g2' contain one space .
I need get the args(may contain space character) from bat file, then I will handle them in the java file.
Could anybody give me a solution? Thanks very much.
On the (DOS/Windows) command line, you should always surround arguments that contain spaces, with quotes. E.g.
start.bat -arg1 "-ar g2" -arg3
Surrounding each and every argument with quotes, even ones without spaces, will not hurt, but your batch script needs to remove the quotes then (see code samples below).
This has been the case for as long as I can remember (pre-Windows 3.1 DOS days). When long filenames (which could include spaces) were implemented, this became more common. E.g.
C:\Users\adam>copy "My Documents" "My Backup Files"
(try it without quotes too).
This is the CMD way, and any programs called from the CMD will understand this correctly.
Code Samples (may be useful for debugging, to see what actually is returned. Run the Batch file or Java class with a list of arguments and play around.)
Batch script (the ~ (tilde) character is the important thing, it removes the surrounding quotes):
#echo off
FOR %%a IN (%*) DO echo [%%~a]
Java (surrounding quotes automatically removed)
public class TestArg {
public static void main(String[] args) {
for (String a : args) {
System.out.println("[" + a + "]");
}
}
}
Isnt it possible to split the string with | character, and then trim the values (left + right) ? This should preserve the spaces inbetween.
You could use something like below... just proof of concept code, the rest you'll need to do yourself... or buy a book on java programming like I did.
public static void main(String argv[])
{
String argument1 = "";
String argument2 = "";
String argument2value = "";
String argument3 = "";
for(int c=0;c<argv.length;c++)
{
if(argv[c].indexOf("-")==0)
{
if(argument1.length() == 0)
{
argument1 = argv[c].substring(1,argv[c].length());
}
if(argument2.length() == 0)
{
argument2 = argv[c].substring(1,argv[c].length());
}
}
else
{
if(argument2.length() != 0)
{
argument2value = argument2value + argv[c]
}
}
}
}

Categories

Resources