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[#]}"
}
Related
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.
Supposedly jjs is the Java 8 version of nashorn, ready for shell-scripting. However when I write a file with execute permission as:
#!/usr/bin/jjs
arguments.forEach(function(v,i,a){print(v);});
Running it produces some not so ideal shell-scripting behavior:
$./file.js
$./file.js one two
java.io.IOException: one is not a file
$./file.js -- one two
one
two
$./file.js file.js -- one two # what were they thinking
one
two
one
two
$
So, I don't ever want this script I'm writing to allow for the arbitrary interpretation of a file after it runs, maybe I should use -- in the shebang like:
#!/usr/bin/jjs --
arguments.forEach(function(v,i,a){print(v);});
But this gets less useful:
$./file.js
jjs>^D
$./file.js one two
jjs>^D
$./file.js -- one two
jjs>
Yes, being dropped into a REPL prompt is exactly what I thought should not happen.
How am I supposed to make it possible to execute a script with arguments that are passed directly and not interpreted by jjs itself such that I can get behavior like:
$./file.js one two
one
two
$
The example works as expected in the JDK 9 version of Nashorn. I'll take care of backporting the required patches so they can appear in one of the upcoming 8u releases.
Update: the required changes are backported to the 8u stream, but it is not clear at what point there will be a release. The early access releases of JDK 9 available from https://jdk9.java.net/download/ have the shebang feature, and also other extensions, such as piping support for the $EXEC builtin.
While waiting for the changes to be backported, I wrote a script to overcome the problem. My jvm is installed in the folder /usr/lib/jvm/jdk1.8.0_101, so I created the following script:
/usr/lib/jvm/jdk1.8.0_101/bin/jjs/bin/jjs-cp.sh:
#!/bin/bash
CP=
if [[ $1 = "--lib="* ]]; then
LIB_FOLDERS=${1:6}
shift
LIB_FOLDERS=$(echo $LIB_FOLDERS | tr ":" "\n")
for FOLDER in $LIB_FOLDERS; do
if [[ $FOLDER = "!"* ]]; then
CP="$CP:${FOLDER:1}"
else
if [ -d $FOLDER ]; then
JARS=$(find "$FOLDER" -type l -o -type f -name "*.jar")
for JAR in $JARS; do
CP="$CP:$JAR"
done
fi
fi
done
if [ -n $CP ]; then
CP=${CP:1}
fi
fi
SCRIPT_FILE="$1"
shift
if [ -n $CP ]; then
/usr/lib/jvm/jdk1.8.0_101/bin/jjs -cp "$CP" $SCRIPT_FILE -- $#
else
/usr/lib/jvm/jdk1.8.0_101/bin/jjs $SCRIPT_FILE -- $#
fi
Then, in my test.js script I can write:
#!/usr/lib/jvm/jdk1.8.0_101/bin/jjs-cp.sh --lib=!.:<full path to classpath folder 1>:<full path to classpath folder 2>
var console = {
log: function(msg) {
java.lang.System.out.println(msg);
}
};
console.log('Hello, world!');
arguments.forEach(console.log);
var MyClass = Java.type('com.acme.MyClass'); // load a class from a jar in the classpath
console.log(MyClass.class); // prints "class com.acme.MyClass"
And I can execute my script with this command line:
~$ ./test.js one two
I have a Java program that spawns a bash script that calls another script. In that second script, I'm finding that the $HOME variable is not set. Here's the gist of it:
In Java:
Process p = new ProcessBuilder("bash", "-l", "/foo/a.sh").start();
// code to actually execute p
/foo/a.sh:
#!/bin/bash
/foo/b.sh
/foo/b.sh:
#!/bin/bash
echo "HOME=$HOME"
This echoes "HOME=". The eventual problem is that $HOME/bin is supposed to be added to my PATH in ~/.profile, but since that's not happening, a bunch of custom executables aren't being made accessible.
I worked around it by doing:
if [ -d ~/bin ] ; then
PATH=~/bin:"$PATH"
fi
And that works fine. But I guess I just want to understand why $HOME wasn't being set. It seems like $HOME and ~ should be largely equivalent, no? There's probably something I'm fundamentally missing about how this environment is getting set up.
I am running Ubuntu 12.04.5, if that makes a difference.
The evidence suggests that HOME is missing from the environment in which the Java app is running. Assuming that the app doesn't explicit unset HOME, the most likely reason is that the app is being started from some context other than a login by the user the app is running as.
It's correct that ~ and $HOME are similar. If HOME is present in the environment, even if it is set to the empty string, ~ will be replaced with $HOME. However, if HOME is not present in the environment, bash will attempt to find the home directory for the currently logged in user, and use that for ~.
eg.
$ bash -c 'echo ~'
/home/rici
$ HOME='Hello, world!' bash -c 'echo ~'
Hello, world!
$ HOME= bash -c 'echo ~'
$ (unset HOME; bash -c 'echo ~';)
/home/rici
Since your workaround requires the equivalent of the last scenario, I conclude that HOME has not been set, or has been unset.
I wanna re-run a jar file from its own (with some additional parameters). How can I do this?
I need the solution to be OS independent.
If I deciphered the question correctly, we are talking about command line interface arguments. For this there's plenty tutorials: http://docs.oracle.com/javase/tutorial/essential/environment/cmdLineArgs.html
The code is simple, like you said yourself:
if ("-server".equalsIgnoreCase(argv)) {
// we are server
} else if ("-client".equalsIgnoreCase(argv)) {
// we are client
}
Now, depending on how you want to execute you program from the OS, there's a number of ways:
$java -jar yourjar.jar -client
Or
$java -cp yourjar.jar com.your.program.Main -client
Same for the "-server".
To run them together, either run them from separate terminal windows (or cmd prompts). Or - if in Linux - you can use ampersand:
$java -jar yourjar.jar -client &
$java -jar yourjar.jar -server &
I have a program in java which takes 0'th aargument as file location like
File f = new File(args[0]);
so when i execute it using a windows batch(.bat) file it works correctly .
but when i execute the same using a linux shell file(.sh) in linux i get ArrayIndexOutOfBoundsException.
WINDOWS BATCH FILE :
#echo off
for /f %%i in ("%0") do set scriptpath=%%~dpi
set cp=%scriptpath%/../lib/*.jar;
java -classpath %cp% com.synchronizer.main.MYSynchronizer %scriptpath% "%1" "%2"
LINUX SH FILE:
export JAVA_HOME=/usr/local/java
PATH=/usr/local/java/bin:${PATH}
THE_CLASSPATH=
for i in `ls ../lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -cp ".:${THE_CLASSPATH}" \
com.synchronizer.main.MYSynchronizer
please help!
It looks like a problem in script (no arguments are passed to the Java program).
You can consider to debug the script like this: debugging scripts
Hope this helps
Your shell script is not passing any parameters:
java -cp ".:${THE_CLASSPATH}" com.synchronizer.main.MYSynchronizer
Try:
java -cp ".:${THE_CLASSPATH}" com.synchronizer.main.MYSynchronizer "$1" "$2"
As stated above, your Linux shell script is not sending any arguments to the Java program that you are trying to start.
And, adding to that, you are not showing us how you run the Linux shell script. If no argument is given on the command line when you start the shell script, no arguments can be passed to your Java application from the shell script.
If you want to see the actual command that is going to be run by your shell script, you can always put "echo" in front of a line and see what all variables are expanded to. This is a simple way to debug shell scripts.