Java exec on Unix - java

I have the Java code below running on Unix (both AIX and Linux), but it doesn't work. If I run this code the file q1.01 is not compressed, and I don't get any exceptions thrown (The file q1.01 exists, and I expect to find the file q1.01.Z after the command runs.) At the command prompt if I type "which compress" it reports back with "/usr/bin/compress". If I type the command "/usr/bin/compress q1.01" at the Unix prompt it works fine. Any ideas on what might be wrong?
String cmd = "/usr/bin/compress q1.01";
Runtime.getRuntime().exec(cmd);

[Later edit: the problem was in the initial description; the OP was passing a wildcard and not q.01. So my answer below is wrong, except for the part in bold. I'm leaving it so the comments after it will make sense.]
It's trying to run /usr/bin/compress as the program name without arguments.
There are many forms of the Runtime.exec() method. You're using the .exec(String) version, which just takes the executable. Instead, you need to use the .exec(String[]) array version, which takes the executable in String[0] and the parameters in String[1..].
.exec() wants a String array for passing arguments.
Try
String[] cmd = new String[] { "/usr/bin/compress", "q1.01" };
Runtime.getRuntime().exec(cmd);
Note that .exec does not call the local command shell. That means we have to do, among other things, wildcard expansion and even some argument parsing before calling .exec(). This is why you can't just pass it your full command line.

There were a couple of problems. One was that I had tried using wildcards, and since the shell isn't invoked they weren't being expanded. The other problem was that I had created very small test files like this: "echo 'abc' >q1.01". This file was so small that compress couldn't compress it any further and so left it alone. (Stupidly, I think when I typed in the command at the shell I used a different filename, which did compress.)
Thanks everyone for the answers. It did help!

You probably need to use an absolute path to the file. Capture the output though, to see what the problem is - see this page for info on how to do that.

This site may be able to provide some clues.

If the process input stream is null, I suspect that Java wasn't even able to spawn the subprocess. What does Process#exitValue() return?
I'd recommend using strace to see what actually happens on the system-call level. The actual exec() arguments and return code would be especially interesting to see.

Related

How to run multiple CMDs with quotes in one terminal in java

I need to execute in java 2 commands in one terminal,
each command contains a path with spaces.
For example:
CMD 1: "C:\user\with space\bat1.bat"
CMD 2: "C:\user\with space\bat2.bat"
The purpose is running CMD 2 only if CMD 1 ran successfully, in the same terminal.
I've tried to use && :
Runtime.getRuntime().exec("\"C:\\user\\with space\\bat1.bat\" && \"C:\\user\\with space\\bat2.bat\"");
But I got the following error:
'\"C:\user\with space\bat1.bat\"' is not recognized as an internal or external command,
operable program or batch file.
How can I run them both and make it recognize each command separately?
You've confused a terminal with execute. These are not the same thing. Your OS can run applications. The terminal isn't "the OS". It's an application. When you type stuff in there, you are not sending it 'to the system', you're just typing in that application. No different from me typing in this very text box in a web browser. I type a letter and it appears. I hit enter and stuff happens.
The shell does a whole boatload of 'parsing' on what you type and then uses the equivalent of Runtime.getRuntime().exec in the language it is written in.
There are a lot of things that /bin/bash, /bin/zsh, /bin/fish, windows's cmd.exe, and all those other shells do. For some of these, it really IS the OS that does it... depending on which OS you're using. It's best to rely on absolutely none of these:
Scour the PATH when you type a non-absolute-path executable to know which one to run.2
Append .exe, .bat, .com, or similar.
A whole bunch of well known commands like cd, ls, mkdir, etcetera.
&&, || and other ways to chain things.
filename substitutions, such as whatever.exe *.txt (the *.txt is 'substitution').1, same goes for ?.
variable substitution, such as /bin/foo $fn.
Redirect pipes such as 2>/dev/null or <myfile.txt.
splitting the command up by separating on spaces and considering the first thing the path of a command and all other things, each individually, a single argument... but then looking at quotes, using those to figure out certain spaces are not separators between parameters, and removing the actual quote characters of course.
Replace ~ with the user's home dir.
And much, much more.
You need to do all of it yourself. That's why you should never use Runtime.getRuntime().exec and always use ProcessBuilder instead. You can set up redirects with that, do the argument splitting on your own. Always specify an absolute path. Don't use * or ? for anything, etcetera.
You can't write, from within java, a magical way to make 2 batch files not open up 2 black boxes. Instead, create a new batch file that runs both batch files (I think you have to do CALL bat1.bat to avoid 3 black boxes showing up), and then run that, and you can't just run the batch file, you run cmd.exe and tell IT to run the batch file. If it's very very simple, you may be able to tell CMD to do it in one go.
Path workingDir = Paths.get(".");
List<String> batOfBatsContent = List.of(
"#ECHO OFF",
"CALL bat1.bat || GOTO :fail",
"CALL bat2.bat",
":fail");
Path megaBat = workingDir.resolve("doEverything.bat");
Files.write(megaBat, batOfBats.stream().collect(Collectors.joining("\r\n"));
ProcessBuilder pb = new ProcessBuilder();
pb.command(System.getenv("COMSPEC"), "/c", batOfBats.getAbsolutePath());
pb.start();
Or possibly:
Path workingDir = Paths.get(".");
ProcessBuilder pb = new ProcessBuilder();
pb.command(System.getenv("COMSPEC"), "/c",
"\"" +
workingDir.resolve("bat1.bat").getAbsolutePath() +
"\"&&\"" +
workingDir.resolve("bat2.bat").getAbsolutePath()
+ "\"");
pb.start();
[1] Actually, windows does do this, probably. Posix OSes (everything that isn't windows, at this point in time) definitely don't.
[2] Java tries to do this, sort of, but it's not particularly reliably. If you don't have to rely on it, don't. It's security-wise dubious in any case to do so.

Calling a Java Program from Cobol

I'm trying to communicate Java and Cobol. I need to call a Java program (with paramaters) from Cobol.
I read some documentation from Microfocus:
http://supportline.microfocus.com/documentation/books/nx40/dijafc.htm
http://supportline.microfocus.com/documentation/books/nx40/dijaco.htm
But I didn't find a real solution, because I need to call an entire program and not a Java Class.
Thanks in advance.
Below is a sample program that will launch an EXE from within a COBOL97 application.
Check CallEXE demo in http://www.netcobol.com/support/code-samples/
When it comes to Microfocus...
One can not CALL an EXE from a Micro Focus INT or GNT, but you can CALL a Non-mainframe program (Micro Focus dialect in MFE) and issue a shell to DOS and from there either execute a command line that executes the EXE or execute the EXE file directly passed on the Micro Focus CALL (x'91' function code =35).
Also, you will not get back any passed parameters since once the DOS shell is closed, no parms can be returned. So the best way to get parms back is to write them to a file.
I am including a sample program that shows this x'91' FC=35 call. As you can see, you can execute a batch file or a command or an EXE directly.
Working-Storage Section.
1 Cmd-Line-Str.
2 Pic X(45)
* value 'RUN $IMSDIR\PCIMS RUNIMS BMP,DBUTIL,DEMO001T'.
* value 'run lorince'.
value 'dir c:\ /o > d.d'.
2 N-1 Pic X Value Low-Value.
1 Call-Func Pic X Comp-X Value 35.
1 Result Pic X Comp-X.
1 Cmd-Line-Len Pic X Comp-X Value 0.
Procedure Division.
P1.
Display Cmd-Line-Str upon Command-Line
Call x'91' using Result, Call-Func, Cmd-Line-Len
If Result = Zeroes
Display 'Call worked'
End-If
Goback.
I hope the post gives you some more information, I have only mainframe knowledge and haven't tried any of this above.
The link you posted explains very well about how we can instantaite a java class. If you are concerned about parameters, then write the Java Class with parameteric constructor and pass the parameters while you instantiate the Class from Cobol.
If you are confused about Java Class and Java Program, then you need to know that Java programs are compiled into .class files at the most you have executable jars containing .class files. But there is nothing like .exe for java.

Java String execution in Linux terminal

I am using StringBuilder to create a string and then trying to execute the string on Linux terminal. But instead of executing whole command, it executed half command and then terminates it. This is my java code snippet:
moteCommand.append("CFLAGS+=-DCC2420_DEF_CHANNEL=1");
moteCommand.append(" ");
moteCommand.append("make telosb install.");
moteCommand.append(moteIdList.get(i).toString());
moteCommand.append(" bsl,");
moteCommand.append(moteAddrList.get(i).toString());
String moteCommand2 = moteCommand.toString();
Process moteProgProcess = Runtime.getRuntime().exec(moteCommand2, null,"/opt/tinyos-2.x/apps/XXX/);
It gives me this error:
Cannot run program "CFLAGS+=-DCC2420_DEF_CHANNEL=1" (in directory "/opt/tinyos-2.x/apps/xxx"): java.io.IOException: error=2, No such file or directory
I don't understand why system process is trying to execute only half of the string. Please let me know if anybody knows the reason.
Thanks.
When you call Runtime.exec(), the characters up to the first space must be the name of the program you want to launch. After that, each "part" between spaces is a separate argument. Note that calling Runtime.exec() is completely different from typing a command in bash (or any other shell...) and pressing enter!! If you type a command that works fine in bash, it doesn't mean it will work with Runtime.exec(). For example, shell commands (which are not external programs) won't work in Runtime.exec().
What you should do is use ProcessBuilder.
Instantiate it, manipulate its Map that represents the environment options (ie, the things you are passing before the command name, such as the cflags, and anything else you might want), set the command name, give the arguments one at a time (the arguments won't get split at spaces, so you can pass paths containing spaces, for instance), etc. You can manipulate the stdin, stdout and stderr in many different ways (such as: use the same as those used by the Java process; or get instances of InputStream and OutputStream to write to and read from the process; or pipe them), and run the process.
Something along the lines:
final ProcessBuilder pb = new ProcessBuilder("make", "telosb", "install" blablablabla);
final Map<String, String> env = pb.environment();
env.put("CFLAGS", "....your options....");
pb.start(); // take the Process instance, and you will be able to read the output, wait for it to finish, get the exit code, etc

How to Clear Console in Java?

I have been pulling my hair for this since quite long time. I have researched for an hour on how to clear a console in Java.
All I found was dirty hacking either by printing a bunch of lines or executing this
Runtime.getruntime.exec("cls/clear");
However, nothing seems to be working for me. Isn't there really any a way of clearing the console in Java like in C (clrscr();). Isn't there any external library by which this can be achieved.
Please let me know if anyone has ever done this before using a proper function, library etc. instead of dirty hacking.
If your terminal supports ANSI escape codes, this clears the screen and moves the cursor to the first row, first column:
System.out.print("\033[H\033[2J");
System.out.flush();
This works on almost all UNIX terminals and terminal emulators. The Windows cmd.exe does not interprete ANSI escape codes.
Try this code
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, it will clear the console.
Runtime.getRuntime().exec("PlatformDepedentCode");
You need to replace "PlatformDependentCode" with your platform's clear console command.
The exec() method executes the command you entered as the argument, just as if it is entered in the console.
In Windows you would write it as Runtime.getRuntime().exec("cls");.
Use the following code:
System.out.println("\f");
'\f' is an escape sequence which represents FormFeed. This is what I have used in my projects to clear the console. This is simpler than the other codes, I guess.
You need to instruct the console to clear.
For serial terminals this was typically done through so called "escape sequences", where notably the vt100 set has become very commonly supported (and its close ANSI-cousin).
Windows has traditionally not supported such sequences "out-of-the-box" but relied on API-calls to do these things. For DOS-based versions of Windows, however, the ANSI.SYS driver could be installed to provide such support.
So if you are under Windows, you need to interact with the appropriate Windows API. I do not believe the standard Java runtime library contains code to do so.
You can easily implement clrscr() using simple for loop printing "\b".
If you are using windows and are interested in clearing the screen before running the program, you can compile the file call it from a .bat file.
for example:
cls
java "what ever the name of the compiles class is"
Save as "etc".bat and then running by calling it in the command prompt or double clicking the file

How to PNGCrush a whole directory tree of PNGs on Windows?

The question is pretty much what is asked in the title.
I have a lot of PNG files created by MapTiler. 24083 files to be exact. They are within many folders which are in many folders i.e. a tree of folders, duh. Thing is, it's the biggest waste of time to manually PNGCrush all of those.
Does anyone have an algorithm to share for me please? One that could recursively crush all these PNGs?
I have a Windows PC and would love to have it rather in Java or PHP than another language (since I already know it well) But else something else might be fine.
Thanks!
You don't need anything special for this, just use the FOR command in the Windows Command Prompt.
Use this line:
FOR /R "yourdir" %f IN (*.png) DO pngcrush "%f" "%f.crushed.png"
The "yourdir" is the root-directory where the input files are stored.
The two %f's at the end:
The first one is the input filename
The second one is the output filename
-ow option added in 1.7.22 to make the operation in-place:
FOR /R "yourdir" %f IN (*.png) DO pngcrush -ow "%f"
See this page for more information of FOR.
The program 'sweep' http://users.csc.calpoly.edu/~bfriesen/software/files/sweep32.zip lets you run the same command on all files in a directory recursively.
See: RecursiveIteratorIterator with RecursiveDirectoryIterator and exec (or similar)
With that you can use:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('%your-top-directory%'));
foreach ($it as $entry) {
if (strtolower($entry->getExtension()) == 'png') {
// execute command here
}
}

Categories

Resources