How can I do Java/Kotlin to CLI? - java

I have a Java/Kotlin program, which gets arguments from String[] args, and I need to make it executable from everywhere from console, without prefixing it with java word. Like only the name of the program and its arguments. How can I do it?
Like git or heroku:
name command

It depends on your operating system, but on Unix the following script would work:
#!/bin/sh
MYSELF=`which "$0" 2>/dev/null`
[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" $java_args -jar ${MYSELF}.jar "$#"
exit 1
You need to append this script at the start of your jar using cat, like the following
cat script.sh my.jar > my-program
And move my-program to some dir in your $PATH. After that, you'll be able to call my-program as usual program.

Related

create shell script for parameterized variable [duplicate]

This question already has answers here:
How to execute a bash command stored as a string with quotes and asterisk [duplicate]
(5 answers)
Closed 3 years ago.
I am very much new to shell script and i want to create and run shell script.
I want to run my java program in two different environment which is simu and prod.
If i am running the program in the simu environment then execute SIMU_RUN else PROD_RUN.
For example i have two directory where file is placed in /data/etl-simu/in/ and /data/etl-prod/in/ and as you can see while reading the file from the directory name i can recognise whether the environment is simu or prod from SIMU_PATH or PROD_PATH variable.
I am not sure if it easy to write such shell script and execute it.
If i just create normal shell script and put the complete SIMU_RUN or PROD_RUN path in that shell script and execute it then in the respective environment then it will run fine.
But as i have two environment then i want to make this shell script flexible instead of creating two separate shell script for simu and prod
#!/bin/sh
SIMU_RUN="cd /opt/env/import/import/current; java -Dlog4j.configurationFile=/opt/import/config/logging/log4j2_Importer.xml -Djava.security.egd=file:///dev/urandom -classpath /opt/runner/lib/*:/opt/import/lib/* runner.Application --config /opt/import/config/import.simu.properties --workflow import --inputDir /data/etl-simu/in"
PROD_RUN="cd /opt/import/import/current; java -Dlog4j.configurationFile=/opt/import/config/logging/log4j2_Importer.xml -Djava.security.egd=file:///dev/urandom -classpath /opt/runner/lib/*:/opt/import/lib/* runner.Application --config /opt/import/config/import.prod.properties --workflow import --inputDir /data/etl-prod/in"
SIMU_PATH="/data/etl-simu/in"
PROD_PATH="/data/etl-prod/in"
MODE=$1
if [ "${MODE}" = SIMU_PATH ]; then
#execute SIMU_RUN
else
#execute PROD_RUN
fi
exit ${EXIT}
Don't store code in a variable, use a function:
#!/bin/sh
run() {
cd /opt/import/import/current &&
java -Dlog4j.configurationFile=/opt/import/config/logging/log4j2_Importer.xml \
-Djava.security.egd=file:///dev/urandom \
-classpath /opt/runner/lib/*:/opt/import/lib/* \
runner.Application \
--config "/opt/import/config/import.${mode}.properties" \
--workflow import \
--inputDir "/data/etl-${mode}/in"
}
mode=$1
case "$mode" in
prod|simu)
run
;;
*) echo "error: invalid mode" >&2
exit 1
;;
esac
Notes:
Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.
I've broken up the very long lines with line continuations: that will make maintainability much easier.
If you make this a bash script, then it's even nicer IMO:
run() {
local -a java_options=(
-Dlog4j.configurationFile=/opt/import/config/logging/log4j2_Importer.xml
-Djava.security.egd=file:///dev/urandom
-classpath "/opt/runner/lib/*:/opt/import/lib/*"
)
local app="runner.Application"
local -a app_options=(
--config "/opt/import/config/import.${mode}.properties"
--workflow import
--inputDir "/data/etl-${mode}/in"
)
cd /opt/import/import/current &&
java "${java_options[#]}" $app "${app_options[#]}"
}

Teaching assistant bash script to automate the process of finding, compiling, and running .java files

Background:
I posted a question on https://unix.stackexchange.com/questions/469680/teaching-assistant-bash-script-to-automate-the-process-of-finding-compiling-an and received some really good advice. Now I'd like to take my process one step further.
Summary of Design:
I'm a TA in University looking to automate testing my student's java code. I am also using this opportunity to grow in my bash skills because I feel like they could be better. My current bash script looks like this:
#!/bin/bash
list='/Users/ajm/Desktop/170Grading/output/list.txt'
score='/Users/ajm/Desktop/170Grading/output/score.txt'
> "$list"
> "$score"
find "$1" -name '*.java' >> "$list"
exec 3< "$list"
while IFS='' read -r -u 3 line || [ -n "$line" ]
do
read -p "> $line (Press Enter to continue)"
echo "the next file is $line" >> "$score"
open -a "Xcode" "$line"
javac -d "/Users/ajm/Desktop/170Grading/runs" "$line" >> class && echo compiled >> "$score" || echo not compiled >> "$score"
echo "standard in string" | cd "/Users/ajm/Desktop/170Grading/runs" java "$class" >> "$score"
done
Point of Contention
Currently, everything works up until the last line before the done. For some strange reason, the output from the java "$class" is not appended to "$score". Any guidance would be greatly appreciated.
Additional Goals
A) I would like to be able to take in additional parameters for my script so that I don't need to keep editing it for each new assignment. For example in:
find "$1" -name '*.java' >> "$list"
I would like to be able to replace the '*.java' with 'string.java'. I know that I can obtain the string as $2 as a command arg for the script, but '$2.java' does not seem to be the correct way of going about this. As an example: say I only want to look at a subset of .java files that end color.java, I would like to be able to say
bash script.sh directory color
and have that perform the task. If there is no $2, the code should default to '*.java'.
My Solution:
After speaking with my professor I have worked out a solution. I would like to note the new script, and what the problems with the old script were, and what changed we made to make this work:
#!/bin/bash
list=/Users/ajm/Desktop/170Grading/output/list.txt
score=/Users/ajm/Desktop/170Grading/output/score.txt
runs=/Users/ajm/Desktop/170Grading/runs
> "$list"
> "$score"
rm -r "$runs"/*
find "$1" -name "*$3.java" >> "$list"
exec 3< "$list"
while IFS='' read -r -u 3 line || [ -n "$line" ]
do
read -p "> $line (Press Enter to continue)"
echo "the next file is $line" >> "$score"
open -a "Xcode" "$line"
javac -d "$runs" "$line" && echo compiled >> "$score" || echo not compiled >> "$score"
class=$(basename "$line")
class=${class%.java}
cd "$runs"
echo "$2" | java -cp "$runs" ${class} >> "$score"
done
Explanation:
list, score, and runs all refer to paths on my computer, in the future, I'd like to make this solution more general for any computer. The lines:
> "$list"
> "$score"
Reinitialize these paths to be empty. In order to reinitialize the runs folder to be empty we use:
rm -r "$runs"/*
Which recursively removes anything inside the run directory. A word of
Caution: because of the asterisk, if runs is improperly set, you may do irreversible damage to your computer.
The code is the same until here:
class=$(basename "$line")
class=${class%.java}
In this step, we grab only the last item in the class directory, and then we remove the .class part of the name, because running:
java code.class
is really telling the jvm to do:
java code.class.class
and so we will encounter errors.
In the last step we use curly braces instead of quotes {} to refer to the file name:
echo "$2" | java -cp "$runs" ${class} >> "$score"
And other than making the $2 and $3 be assigned at execution as opposed to when the script is run, the code is the same.
I hope that if someone runs into this issue in the future, this answer will be helpful. I will be refactoring a more general purpose script for this usage and I may post it as an addendum in the future.
You're not executing Java. You're doing
cd "/Users/ajm/Desktop/170Grading/runs" java "$class" >> "$score"
The cd command sees 3 arguments and ignores "java" and "$class".
Try instead:
cd "/Users/ajm/Desktop/170Grading/runs"
echo "standard in string" | java "$class" >> "$score"
Or if your CLASSPATH environment variable doesn't contain . as one of the paths, you may explicitly set the classpath without changing directory:
echo "standard in string" | java -cp "/Users/ajm/Desktop/170Grading/runs" "$class" >> "$score"

Start Java Program by Script in Linux

I want to start my java program by script. I also want to include .jar files by executing the script.
My script looks like this:
if [ -d ./bin ]; then
rm -fr ./bin
fi
mkdir ./bin
javac -sourcepath ./src -d ./bin -cp ./../Jars/CFMgr.jar ./src/gui/App.java
if [ "$?" != "0" ]; then
echo "compile errors..."
exit -1
fi
java -classpath ./bin:./../Jars/CFMgr.jar:./../Jars/ojdbc14.jar gui.App
Every time I execute it with this command ./script.sh in the linux terminal, I get the following error:
https://s4.postimg.org/kevatu0nx/Unbenannt.png
test:
java -cp "./bin/*:./lib/*" com.YourClass
You are compiling only App.java , which need Panel.java. so compile all the classes in gui package at the same time.
One solution is to export your java program to an executable jar and then:
java -jar yourProgram.jar

Bash - Find a java class and its jar directory by searching whole system

I have the following script which does close to what I need; that is, to search the whole system for jar files that contain a specific java class file. My only issue with this script is getting it to acknowledge when it has found a class file in the jar based on the class name I pass in. The script at the moment only gives me back the class package inside the jar, not the jar it is in, which means its kind of useless. I'm trying to use $? to check if the search command was successful and if so echo the directory it was in into a file. It's always returning success(0) though, so every jar location it finds it is appending to the file. I'll stop talking now, can someone run this script and see what it is doing vs what I am trying to do?
if [ $# -ne 1 ]
then
echo "Need to provide class name as argument"
exit 1
fi
> findClassResults.txt
for i in $(locate "*.jar");
do
if [ -d $i ]
then
continue
fi
if jar -tvf $i | grep -Hsi $1.class 1>/dev/null
then
potentialMatches=`jar -tvf $i | grep -Hsi $1.class`
exactMatch=`echo $potentialMatches | grep -o \/$1.class`
if [ ! -z $exactMatch ]
then
echo "matches found: " $potentialMatches >> findClassResults.txt
echo ".....in jar #: " $i >> findClassResults.txt
echo -e "\n" >> findClassResults.txt
fi
fi
done
Edit: the above is now the working script. It will find any .class file and the location of its jar on the system by passing in the name of the class e.g. ./findClass.sh MyClass
Redirect the output of the loop as a whole to your results file, not each command individually (and use a while loop to iterate over the results, not a for loop):
< <(locate "*.jar") while read -r i
do
if [ -d "$i" ] #mvn repos have dirs named as .jar, so skip...
then
continue
fi
if jar -tvf "$i" | grep -q -Hsi "$1.class"
then
echo "jar location: $i"
fi
done | tee -a findClassResutls.txt
the $? you're using there is on the tee command, which I bet pretty well always succeeds. You probably want Pipe output and capture exit status in Bash

Executing java program from bash script does not work

I am trying to run a java program (weka) from a bash script. The script takes as arguments an inputfile, an outputfile and the content of file containing the command to run the java program (environment variable $CMD). The script does not work as I wish and informs me that I use an unknown option for java. I tried to echo the command that the program sends to the shell, and the output is exactly the right command. So I assume that the echo output and the command sent to the shell are not the same.
So please tell me: What did I do wrong?
What is the difference between the output I get...
echo "java $(cat $CMD) $in > $out"
...and the command the computer gets?
java "$(cat $CMD)" $in > $out
If more information is needed, please comment!
Edit:
For those familiar with weka (or familiar with java), this is what I want to get, and what is printed to me by echo:
java -cp /usr/share/java/weka.jar weka.filters.supervised.attribute.AttributeSelection -E "weka.attributeSelection.ClassifierSubsetEval -B weka.classifiers.bayes.NaiveBayes -T" -S "weka.attributeSelection.BestFirst -D 1 -N 14" -i /home/aldorado/weka_examples/iris.arff > /home/aldorado/weka_examples/irisselected131113.txt
Add set -x in before the line which causes trouble.
That will make the computer print the command again as it understood it. You will see something like
+ 'java' '-classpath weka.jar name.of.the.main.Class' 'inputFile' > 'outputFile'
Note that quotes which the shell uses to tell you "this was one word / argument for me". It's very useful to notice problems with white space and quoting.
Note that it is very hard to get something like java "$(cat $CMD)" $in > $out working. I suggest to move the java into $CMD. That will allow you to say:
bash "./$CMD" $in > $out
or, if you make the file executable:
"./$CMD" "$in" > $out
Use "$1" in the file $CMD to get a property quoted reference to "$in":
cp="weka.jar"
cp="$cp;other.jar"
cp="$cp;more.jar"
cp="$cp;foo.jar"
java -classpath "$cp" name.of.the.main.Class "$1"

Categories