Exit code of Java not coming in Bash - java

I have a bash file:
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/bin/svnlook
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]")
echo "\n$LOGMSG" >> /dev/tty
javac ~/Desktop/SomeClass.java
java ~/Desktop/SomeClass $LOGMSG
STATUS=$?
echo "\n" >> /dev/tty
echo $STATUS >> /dev/tty
exit 0
which calls this java file:
public class SomeClass {
public static void main(String[] args) {
String result = "";
for (String s: args) {
result = result + " " + s;
}
String regex = ".*\\bHello\\b.*";
if(result.matches(regex)) {
System.out.println("It matches");
System.exit(0);
} else {
System.out.println("It does not match");
System.exit(42);
}
}
}
I have never in the Java file have exited with the exit code of 1. However when I echo the status in the bash file, it always shows me '1' What can be the reason behind this?

The error code is because Java is failing to start. You aren't specifying the class to be run correctly.
If I have a class located in my desktop directory, I would need to use the following to run it from another directory:
java -cp ~/Desktop SomeClass
assuming that SomeClass has no package specified. If you have package org.foo.bar; at the top of the file, you would need to use
java -cp ~/Desktop org.foo.bar.SomeClass

Related

How to run tools installed with Homebrew or MacPorts from Java?

I'm trying to do some automation on MacOS with Java.
no problems when running the commands manually from a terminal
i assume it works because of <user.home>/.zprofile
the commands are not found when trying to execute them via ProcessBuilder
How can I execute commands with the same environment as if running a zsh terminal manually?
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Test {
public static void main(String[] args) throws Exception {
// these commands work
run("/bin/sh", "-c", "echo $PATH");
run("/bin/bash", "-c", "echo $PATH");
run("/bin/zsh", "-c", "echo $PATH");
// these commands all work when I run them manually in a terminal
// but fail here with "zsh:1: command not found: ..."
run("/bin/zsh", "-c", "node -v");
run("/bin/zsh", "-c", "npm -v");
}
private static void run(String... command) throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.redirectErrorStream(true);
processBuilder.command(command);
Process process = processBuilder.start();
try(BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
for(String line = br.readLine(); line != null; line = br.readLine()) {
System.out.println(line);
}
}
System.out.println("return value: " + process.waitFor());
}
}
Output:
/usr/bin:/bin:/usr/sbin:/sbin
return value: 0
/usr/bin:/bin:/usr/sbin:/sbin
return value: 0
/usr/bin:/bin:/usr/sbin:/sbin
return value: 0
zsh:1: command not found: node
return value: 127
zsh:1: command not found: npm
return value: 127
After reading way too many articles about shells, and studying shell init diagrams, I decided to go with Zsh.
The reason was this blog post, which indicated that Zsh seems to have at least one init file that is executed for all possible shell variants (login, non-login, interactive, non-interactive etc).
I moved all my environment setup (PATH and LANG) to /etc/zshenv, deleted /etc/zprofile and all ~/.z* files.
I also changed the shell for both root and my user to Zsh (for the user this can also be done via system preferences):
dscl . -delete /Users/root UserShell && dscl . -create /Users/root UserShell /bin/zsh && dscl . -read /Users/root UserShell
dscl . -delete /Users/reto UserShell && dscl . -create /Users/reto UserShell /bin/zsh && dscl . -read /Users/reto UserShell
Now I get the same environment for:
SSH as root
SSH as user
Terminal.app
Processes started from Java
And pretty much everything else so far
So far so good. Test program output:
/usr/bin:/bin:/usr/sbin:/sbin
return value: 0
/usr/bin:/bin:/usr/sbin:/sbin
return value: 0
/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
return value: 0
v14.17.0
return value: 0
6.14.13
return value: 0

How to execute 'nohup' command through JAVA

I have a requirement where I need to execute 15 to 20 java programs parallely in the background. We can use nohup command and execute it directly but I want to execute this nohup command from another java program. I did some research on it and created a java program. but this below java program is working when I use java command, but if I use nohup then its failing
public static void main(String[] args) throws Exception {
String sourceFileName = args[0];
String targetFileName = args[1];
String type = args[2];
String logFileName = args[3];
Integer count = new Integer(args[4]);
// Below command is working
String command = "java -cp \"test-jar.jar\" com.test.MyTestClass ";
// Below command is not working
// String command = "nohup java -cp \"test-jar.jar\" com.test.MyTestClass ";
for(int i=1; i<=count; i++){
String cmd = command+sourceFileName+"_"+i+" "+targetFileName+"_"+i+" "+type+" 2>>"+logFileName+"_"+i+".log &";
runProcess(cmd);
}
}
private static void runProcess(String command) throws Exception {
Process pro = Runtime.getRuntime().exec(command);
pro.waitFor();
System.out.println(command + " exitValue() " + pro.exitValue());
}
For testing purpose I have taken the count as 3, If I use nohup command getting below output
nohup java -cp "test-jar.jar" com.test.MyTestClass source-file_1 target-file_1 TEST 2>>log-file_1.log & exitValue() 1
nohup java -cp "test-jar.jar" com.test.MyTestClass source-file_2 target-file_2 TEST 2>>log-file_2.log & exitValue() 1
nohup java -cp "test-jar.jar" com.test.MyTestClass source-file_3 target-file_3 TEST 2>>log-file_3.log & exitValue() 1
I kept the test-jar.jar in the same path from where I am executing this program.
Issue is because of 2 separate projects.
My class is in my-test project and the class which I want to execute is in test-jar project. I added test-jar dependency in 'my-test' project. Still faced the same issue. I added/copied My class in the test-jar file then I executed it. Now its working for both java and nohup commands

Java delete files unix way (unlink header)

I'm having an issue where archival module written in Java fails to clean files shared via smb if opened by network users during cleanup. Below is simplified version of code for file cleanup:
private static boolean moveFile(String sourceFilePath, String targetFilePath) {
boolean fileStatus = false;
File sourceFile = new File(sourceFilePath );
File targetFile = new File(targetFilePath );
if(sourceFile.canRead() && sourceFile.canWrite() ) {
if(targetFile.exists()) {
fileStatus = (new File(targetFilePath)).delete();
if(!fileStatus) {
Logger.ERROR("Target deletion failed");
}
}
fileStatus = sourceFile.renameTo(new File(targetFilePath));
if(!fileStatus) {
Logger.ERROR("RenameTo method failed");
return false;
} else {
Logger.INFO("Move succeeded");
return true;
}
} else {
Logger.ERROR("Cannot read file");
return false;
}
}
It works fine when I test it in two Linux sessions:
session A:
cat -v /dev/zero > sourceFile.txt
session B:
java -jar JavaUnixFileRemovalTest.jar sourceFile.txt targetFile.txt
But fails in production when working with network shares and users.
What I'd like to implement instead is to copy file to archive folder and unlink the header. This way if user still has the file opened he'll continue accessing the content, while name is removed from the file system so nobody else can see the file.
So the question is if there's a way to unlink file header in Unix by native Java means without explicitly calling unlink command
After some research I decided to approach this problem in a bit different way and cast powerful lost magic of the Ancients - that is, use native system C calls with help of JNA (Java Native Access)
Here's an example of the code with some explanations for JNA first-time users:
package com.WeLoveStackOverflow.JavaJNAUnlinkTest;
import java.io.File;
import com.sun.jna.Library;
import com.sun.jna.Native;
public class Main {
private static CStdLib cStdLib;
// Here you specify prototypes of native C methods to be called during runtime
// Because unlink(char *path) uses pointer to const char as argument, a wrapper class StringByReference is used to convert data types
// Link to other examples at the end of this post
public interface CStdLib extends Library {
int unlink(StringByReference path);
}
public static void main(String[] args) {
// Here I'm declaring libc usage, but you can link anything. Even your own libraries
cStdLib = (CStdLib)Native.loadLibrary("c", CStdLib.class);
Logger.INFO("Source file: " + args[0]);
Logger.INFO("Target file: " + args[1]);
moveFile(args[0],args[1]);
}
private static boolean moveFile(String sourceFilePath, String targetFilePath) {
boolean fileStatus = false;
File sourceFile = new File(sourceFilePath );
File targetFile = new File(targetFilePath );
if(sourceFile.canRead() && sourceFile.canWrite() ) {
if(targetFile.exists()) {
fileStatus = targetFile.delete();
if(!fileStatus) {
Logger.ERROR("Target deletion failed");
}
}
fileStatus = sourceFile.renameTo(targetFile);
if(!fileStatus) {
Logger.ERROR("RenameTo method failed");
Logger.INFO("Trying to copy file and unlink the original");
// ToDo: add copy method
// That's where we convert String to char*
StringByReference unlinkPath=new StringByReference(sourceFilePath);
int status=cStdLib.unlink(unlinkPath);
if(status==0){
Logger.INFO("Unlink succeeded");
}else {
Logger.ERROR("Unlink also failed");
return false;
}
} else {
Logger.INFO("Move succeeded");
}
} else {
Logger.ERROR("Cannot read file");
return false;
}
return true;
}
}
And class for converting data types:
package com.WeLoveStackOverflow.JavaJNAUnlinkTest;
import com.sun.jna.ptr.ByReference;
public class StringByReference extends ByReference {
public StringByReference() {
this(0);
}
public StringByReference(String str) {
super(str.length() < 4 ? 4 : str.length() + 1);
setValue(str);
}
private void setValue(String str) {
getPointer().setString(0, str);
}
}
So what we've got in the end? A nice Java unlink utility! test scenario: create a text file in session A, open it in less in session B and run java code in session A. Works as expected:
[me#server1 JavaFileTest]$ lsof | grep sourceFile
less 12611 me 4r REG 253,0 0 73 /home/me/JavaFileTest/sourceFile (deleted)
This is the article I used as a reference:
http://jnaexamples.blogspot.com/2012/03/java-native-access-is-easy-way-to.html
It contains other good examples of wrapping data types for C calls
Tips:
Make sure you have both JNA and JNA-platform files in your classpath
JNA 4.4.0 requires GLIBC_2.14. If you're getting this error then
simply downgrade JNA (4.2.2 worked for me)
Exception in thread "main" java.lang.UnsatisfiedLinkError: /lib64/libc.so.6: version 'GLIBC_2.14' not found
File.delete seems to behave as "unlink".
Here's an example
import java.io.*;
public class Main {
public static void main(String args[]) throws InterruptedException, IOException {
File invisibleFile = new File("invisiblefile");
invisibleFile.createNewFile();
FileWriter fw = new FileWriter(invisibleFile);
System.out.println("file created");
Thread.sleep(5000);
boolean deleted = invisibleFile.delete();
if(!deleted) {
System.out.println("error deleting file");
System.exit(1);
}
fw.write("hello");
fw.flush();
System.out.println("file deleted");
// 'ls invisiblefile' does not return anything
// but the file is still held open by the process:
// lsof -p $(ps -ef | awk '/[I]nvisibleFile.java/ {print $2}') | awk '/invisiblefile/ {print "size:" $7; print "inode:" $8}'
Thread.sleep(5000);
fw.close();
System.out.println("file closed");
Thread.sleep(5000);
// after closing file, it is completely gone
System.out.println("end");
}
}
And here's a terminal session to check the program's behaviour:
23:30:07 % java InvisibleFile.java
file created
^Z
zsh: suspended java InvisibleFile.java
23:30:11 % ls invisiblefile
invisiblefile
23:30:14 % fg %1
[1] - continued java InvisibleFile.java
file deleted
^Z
zsh: suspended java InvisibleFile.java
23:30:21 % ls invisiblefile
ls: invisiblefile: No such file or directory
23:30:23 % lsof -p $(ps -ef | awk '/[I]nvisibleFile.java/ {print $2}') | awk '/invisiblefile/ {print "size:" $7; print "inode:" $8}'
size:5
inode:33745509
23:30:30 % fg %1
[1] - continued java InvisibleFile.java
file closed
^Z
zsh: suspended java InvisibleFile.java
23:30:37 % lsof -p $(ps -ef | awk '/[I]nvisibleFile.java/ {print $2}') | awk '/invisiblefile/ {print "size:" $7; print "inode:" $8}'
23:30:42 % fg %1
[1] - continued java InvisibleFile.java
end
23:30:47 %

Automating jar input

I have a jar file which asks user the value of n. And adds the values entered. When the jar is executed from cmd.exe, works well. But when invoked from .bat file, it is not prompting for the input rather executes the further statements. I tried using pipe,as,
(echo 3
echo 10
echo 20
echo 30)| java -jar add.jar
but didn't work.How can I automate the input?
Note: values are not accepted as arguments, but as a prompt.
Without knowing something about the code it's hard to tell why it's not working for you.
See below a simple working example
Add.java
import java.util.Scanner;
public class Add {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int sum = 0;
while (scanner.hasNextInt()) {
int value = scanner.nextInt();
sum += value;
System.out.println("sum = " + sum);
}
}
}
run.bat
#echo off
(echo 2
echo 10
echo 20
echo 30
echo end ) | java -jar Add.jar
compile and build the jar
javac Add.java
echo Main-Class: Add > manifest.mf
jar cmf manifest.mf Add.jar Add.class
run the batch file
run.bat
output
sum = 2
sum = 12
sum = 32
sum = 62

unexpected result while communicating with another process's stdin

My project directory has the 3 files below.
rndbet/rndbet.py
while True:
s = input()
if s == "exit":
exit()
else:
print("I'm rndbet: " + s)
rndbet/start
python3 rndbet.py
mjhd.java
import java.io.PrintStream;
import java.util.Scanner;
public class mjhd {
public static void main(String[] args) throws Exception {
Process process = new ProcessBuilder("bash", "-c", "cd rndbet&&./start").start();
new Thread(new Runnable() {
#Override
public void run() {
Scanner in = new Scanner(process.getInputStream());
while (in.hasNextLine()) {
System.out.println("<- rndbet: " + in.nextLine());
}
}
}).start();
Scanner in = new Scanner(System.in);
PrintStream out = new PrintStream(process.getOutputStream(), true);
while (true) {
out.println(in.nextLine());
} //this part is actually broken; it shouldn't be an infinite loop
//just for testing
}
}
When I type bash -c "cd rndbet&&./start" directly from the command line, below happens.
$ bash -c "cd rndbet&&./start"
hi
I'm rndbet: hi
exit
But running the java program behaves differently.
$ java mjhd
hi
<- rndbet: I'm rndbet: hi
exit
<- rndbet: I'm rndbet: exit
exit
<- rndbet: I'm rndbet: exit
So now the Python script doesn't get the exit command correctly. Please help me fix this problem.
I've just found a problem that when the Python script is run via Java, an extra character of ASCII value 13 is always appended at the end of the sent text. What is a possible fix?
Okay I found a simple answer.
Changing out.println(in.nextLine()); to out.print(in.nextLine() + '\n') works.

Categories

Resources