I checked quite a lot of other answers for this question on SO, but none of them really seem to work consistently, and correctly. Also, the examples weren't fitting my use case.
I have a java application jar which has a main class. I want to run it with the following arguments:
-Xms1300m -Xmx1300m -classpath "myClassPath;anotherone;anotherOne" -Xdebug -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
I am always getting simply the following when I try to run it using the following command on my powershell script (not command line)
Start-Process java -ArgumentList '-Xms1300m -Xmx1300m -classpath "myClassPath;anotherone;anotherOne" -Xdebug -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 the.jar.in.myClassPath.mainClass startArgs
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id SI ProcessName
------- ------ ----- ----- ----- ------ -- -- -----------
6 2 204 704 7 0.00 3588 1 java
My java home path is correctly set in environment variables so there's nothing wrong there.
I ran an echo of the argument set and they look correct. I am kind of stuck here to figure out why this causing a problem? Powershell is more complicated as opposed to DOS because when I run it in DOS Command Prompt, it just works. So what has gone wrong for me here?
Regards,
Why Start-Process? Just run the command, quoting the needed parameters. You should be able to just run it this way:
java -Xms1300m -Xmx1300m -classpath "myClassPath;anotherone;anotherOne" -Xdebug "-Djava.compiler=NONE" "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
Notes:
Quote the the argument for -classpath since it contains ; characters.
Quote -D and its attached argument because it contains the . character.
Quote -X and its attached argument because it contains , and = characters.
Basically: Quote a parameter that contains characters that are otherwise syntactically meaningful to PowerShell.
You can troubleshoot executable parameter passing using a handy program I wrote called showargs.exe, which you can get from downloading the code associated with the following article:
IT Pro Today - Running Executables in PowerShell
Related
I have a powershell script that is working and runs a java executable. Before I was generating a bunch of powershell script files that were run through the command prompt. Now I want to make it so there does not need to be file creation.
Here is what the line looks like from the working (.ps1) file:
java <mem opts here> "-Doption1=3" "-Doption2=`` ` ``"true`` ` ``" jar.exe
I want to be able to do something like this in command prompt:
Powershell -Command "java <mem opts here> "-Doption1=3" "-Doption2=`` ` ``"true`` ` ``" jar.exe"
Even just asking this question I am having problems with the escape characters. What is the proper way to handle escape characters when you have quotes in quotes in quotes when calling java through powershell through command prompt? (I understand it is a bit messy)
You can lessen the quoting headaches if you focus just on the parts that require quoting (assuming that option value true truly needs quoting):
REM From cmd.exe
C:\> powershell -Command java -Doption1=3 -Doption2="'\"true\"'" jar.exe
The above will make java.exe see:
java -Doption1=3 -Doption2="true" jar.exe
As you can see, even this simple case of the desired resultant quoting is quite obscure, because you're dealing with 3 layers of interpretation:
cmd.exe's own interpretation of the initial command line
PowerShell's interpretation of the arguments it receives.
How PowerShell's translates the arguments into a call to an external program (java.exe).
In any event, the final layer of interpretation is how the target program (java.exe) parses the command line.
That said, in order to call java.exe, i.e. an external program, you don't need PowerShell at all; invoke it directly:
REM From cmd.exe
C:\> java -Doption1=3 -Doption2="true" jar.exe
This is my exact batch file. I have tried to convert it doing some research online and get an error
"Failed to execute child process "/home/pi/Desktop/TeachVal/TeachValLinuxShell" (No such file or directory)
echo off
cls
echo Running TeachVAL II...
set path=%path%;/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/bin
java -classpath comm.jar;Robot.jar;TeachVAL TeachVAL
cls
exit
This one is my attempt at translating.
#!/bin/bash
set +v
clear
echo "Running TeachVAL II..."
java -cp ".dir1;dir2;path/home/pi/Desktop/TeachVAL/comm.jar;
path/home/pi/Desktop/TeachVAL/Robot.jar;/home/pi/Desktop/TeachVAL/TeachVAL"
clear
exit
Welcome to Linux--life is good here, but there are a few things that work slightly differently, when compared to Windows.
One difference is that Windows uses semicolon (;) to separate entries in a list of paths, but Linux uses colons (:) for that purpose.
So, the Windows command:
java -classpath comm.jar;Robot.jar;TeachVAL TeachVAL
would correspond to this on Linux:
java -classpath comm.jar:Robot.jar:TeachVAL TeachVAL
In general, on Linux, semicolons are used to put multiple command lines into a single line. Once you've learned that, I think you can then understand why:
java -cp .dir1;/home/pi/Desktop/TeachVAL/TeachVAL
would be the same as:
java -cp .dir1
/home/pi/Desktop/TeachVAL/TeachVAL
That would run java (with no class to be executed) and then try to run "/home/pi/Desktop/TeachVAL/TeachVAL" which can't be found.
There are many more differences to learn; here's a page that will help you get started: http://tldp.org/LDP/abs/html/dosbatch.html
I'm trying to restart process when OOME happens. Java binary is launched using two shell scripts, one of them imports other. I don't have any control of the first one but can modify the second one as I want.
This is a prototype what I'm trying to do:
First shell script test.sh:
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Xmx10m"
. test1.sh
echo $JAVA_OPTS
java $JAVA_OPTS $es_params TestMemory
Second shell script test1.sh:
#!/bin/sh
pidfile="test.pid"
touch $pidfile
params="$parms -Dpidfile=$pidfile"
kill_command="kill -9 \$(cat $pidfile)"
dir=$( cd $(dirname $0) ; pwd -P )
path="$dir/$(basename $0)"
start_command="$path $#"
restart_command="$kill_command;sleep 2;$start_command"
JAVA_OPTS="$JAVA_OPTS -XX:OnOutOfMemoryError=\"$restart_command\""
Generally what it does is JAVA_OPTS is constructed inside test1.sh and then used to run Java binary, which just writes PID in pidfile and then creates OOME.
Problem happens during execution, java can't understand what is a parameter and what is a class to run. I think it might be a problem of quoting, I tried different ways to escape JAVA_OPTS, but without any result. I'm either getting:
Unrecognized option: -9
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Or
Error: Could not find or load main class "-XX:OnOutOfMemoryError=kill
If I just take a value of JAVA_OPTS and put it manually in test.sh it runs perfectly.
Any ideas how can I change test1.sh to make it work? I think I tried almost every possible way of putting double and single quotes, but without any success. Also if I put restart_command in restart.sh file and use it instead of the variable, it works fine.
After running set -x I saw that shell modifies every single space character to ' ' - adds ' on both sides. Escaping doesn't gives any result. Any idea how to avoid this? So final commend is:
+ java -Xmx10m '"-XX:OnOutOfMemoryError=kill' '$(cat' 'test.pid);sleep' '2;/Users/davidt/test/TestMemory/bin/test.sh' '")' -Des.pidfile=test.pid TestMemory
Update
I can run simplified command successfully
java "-XX:OnOutOfMemoryError=echo 'Ups'" $es_params TestMemory
But it seems a general problem, shell just hates spaces into variables I guess:
JAVA_OPTS="\"-XX:OnOutOfMemoryError=echo 'Ups'\""
set -x
java $JAVA_OPTS TestMemory
This script fails and the last line is interpreted as:
java '"-XX:OnOutOfMemoryError=echo' ''\''Ups'\''"' TestMemory
I tried different options to escape
This is a shell problem. Based on the evidence, I'd say that one of the ; characters ... and possibly some why space ... is being interpretted by the shell when you don't want / need this to happen.
If you run set -x in the shell before running the command that is trying to start the JVM, you will see the actual command that is being used.
It seems shell translates every single space to ' ',
Not exactly. The single quotes are inserted by the shell into the output you are getting from set -x. They simply indicating where the argument boundaries are. They are not really there ... and they are certainly NOT being passed to the java command.
Any idea how to [a]void it?
What you need to do is start from the (final) command that you are trying execute ...
java -Xmx10m -XX:OnOutOfMemoryError="kill NNNN;sleep 2;/Users/davidt/test/TestMemory/bin/test.sh" -Des.pidfile=test.pid TestMemory
... and work backwards, so that the shell variables, expansions and escaping give you what you need.
The other thing to note is that this:
java -Xmx10m -XX:OnOutOfMemoryError="kill $(cat test.pid); ..."
probably won't work. The kill $(cat test.pid) command is using shell syntax and requires shell functionality to interpolate the contents of the PID file. I doubt that the JVM is going to know what to do with that. (Or more accurately. It will do what you have literally told it to do, but that will not be what you want ...)
If you really need to interpolate the pid file content when the restart command is run as you appear to be trying to do, then suggest that turn the restart command into a free-standing shell script, and set the file mode so that it is executable. It will be simpler and a lot easier to get working.
As a general piece of advice, is is a bad idea to be too clever with shell scripts. The exact semantics of variable expansion and command parsing are rather tricky, and it is easy to get yourself really confused ... if you are trying to do this at multiple levels.
I ended up put the script I wanted to execute in a separate file and gave it as a parameter to JVM to execute when OOME happens.
echo "echo 'UPS'" >> oome_happened.sh
JAVA_OPTS="\"-XX:OnOutOfMemoryError='oome_happened.sh'\""
set -x
java $JAVA_OPTS TestMemory
Like #DaTval said, you should put the command in a script. The script should be someting like.
#!/bin/bash
kill -9 $PPID
Kill the caller of scripts.
I've searched throughout this site and tried a few solutions when receiving this message but nothing seems to work.
I am trying to invoke a shell script on Ubuntu 12.04.2 (with java-7-openjdk-amd64) that runs a java program and then I get a "Error: Could not find or load main class com.xx" error.
This is how my script invokes Java:
"$JAVA" $server_jvmargs $javaProps -Dxx.home="$XX_HOME" -Duser.dir="$XX_HOME" -cp $client_classpath $mainclass $args
And the arguments you see above are defined as follows:
args=$*
javaProps=
mainclass=com.xx
server_jvmargs="-Djava.awt.headless=true -Xms1024m -Xmx1024m $jvmargs"
XX_HOME="`pwd`/../.."
client_classpath="$XX_HOME/lib/client/patch.jar;$XX_HOME/lib/client/xyx-xxx.jar;$clientlibs;$XX_HOME/lib/server/standard-1.1.2.jar;$publictilesource;$respath;$XX_HOME/lib/client/xxmainclass.jar"
The mainclass variable is in the classpath located in the xxmainclass.jar file so I'm not sure as to why it cannot find it?
Does anyone have any ideas on what could be going on?
To see what actually happens when you run your script, invoke it with bash -x, or put set -x at the top; this will print each command before it's run, so you can see how it's actually starting the JVM. Without this information, it's hard to come up with a better diagnosis. That said...
You've been copying off Tomcat's startup scripts, it looks like. Don't; they're awful.
Something a little more correct on the shell side might look like this:
args=( "$#" )
javaProps=( )
mainclass=com.xx
server_jvmargs=( -Djava.awt.headless=true -Xms1024m -Xmx1024m "${jvmargs[#]}" )
XX_HOME="$PWD/../.."
client_classpath="$XX_HOME/lib/client/patch.jar:$XX_HOME/lib/client/xyx-xxx.jar:$clientlibs:$XX_HOME/lib/server/standard-1.1.2.jar:$publictilesource:$respath:$XX_HOME/lib/client/xxmainclass.jar"
java \
"${server_jvmargs[#]}" \
"${javaProps[#]}" \
-Dxx.home="$XX_HOME" \
-Duser.dir="$XX_HOME" \
-cp "$client_classpath" \
"$mainclass" "${args[#]}"
The use of ${foo[#]} expands the array foo with literal contents. Note that foo must be created as an array in this case, and you need to be using a shell that supports arrays (so your script needs to start with #!/bin/bash, not #!/bin/sh).
See http://mywiki.wooledge.org/BashFAQ/005 for an introduction to arrays in bash.
use a : instead of a ; in your classpath.
unix just rolls that way.
Try this:
Java -jar pathToYOurFile.jar
Please check if line end character is OS specific in your shell script
I'm trying to write a BASH script to get my Java program to run(common issue, right?). I just can't quite get it to work. After many edits, here's how I am trying to set the classpath and then execute the program:
java -classpath 'cygpath -u "/cygdrive/c/Projects/common/lib/rome-1.0.jar:/cygdrive
/c/Projects/common/lib/jdom-1.0.jar:/cygdrive/c/Projects/common/lib/jsoup-1.6.1.jar:
/cygdrive/c/Projects/common/lib/mysql-connector-java-5.1.18-bin.jar:/cygdrive/c/Projects
/Freereader/bin/"' com.free.syndication.SQLfeeder
Sorry the the jumble, I'm just trying to do everything at once. It tells me that the main class of my program cannot be found!((
Any ideas?
Java classpath uses semicolon as the token separator.
Use backticks instead of single quotes
Try:
java -classpath `cygpath -u "/cygdrive/c/Projects/common/lib/rome-1.0.jar;/cygdrive
/c/Projects/common/lib/jdom-1.0.jar;/cygdrive/c/Projects/common/lib/jsoup-1.6.1.jar;
/cygdrive/c/Projects/common/lib/mysql-connector-java-5.1.18-bin.jar;/cygdrive/c/Projects
/Freereader/bin/"` com.free.syndication.SQLfeeder
In bash, the syntax $(command) is clearer than the backticks `command`
cygpath has a -p option to convert PATH-like values (as opposed to single path names) between Windows and Unix, i.e.
cygpath -pu 'C:\Users\me\bin;C:\Users\me\project\bin' will give /cygdrive/c/Users/me/bin:/cygdrive/c/Users/me/project/bin
cygpath -pw will do the same in the opposite direction
Note that cygpath -u "/cygdrive/c" (as in your question) will not change anything, since the directory name is already in the desired (Unix) syntax. You could omit it just as well.
So, the command becomes:
CP="C:/Projects/common/lib/rome-1.0.jar;C:/Projects/common/lib/jdom-1.0.jar;C:/Projects/common/lib/jsoup-1.6.1.jar;
C:/Projects/common/lib/mysql-connector-java-5.1.18-bin.jar;C:/Projects
/Freereader/bin"
# for a Windows Java binary:
java -classpath "$(cygpath -pw "$CP")" com.free.syndication.SQLfeeder
# for a Unix Java binary:
java -classpath "$(cygpath -pu "$CP")" com.free.syndication.SQLfeeder
Alternatively, you can start with a Unix-style class path, but the commands stay the same. In either case, you can of course omit the call to cygpath if the class path is already in the desired syntax.
Don't you need backticks?
java -classpath `cygpath -u "/cygdrive/c/Projects/common/lib/rome-1.0.jar:/cygdrive
/c/Projects/common/lib/jdom-1.0.jar:/cygdrive/c/Projects/common/lib/jsoup-1.6.1.jar:
/cygdrive/c/Projects/common/lib/mysql-connector-java-5.1.18-bin.jar:/cygdrive/c/Projects
/Freereader/bin/"` com.free.syndication.SQLfeeder
You must use backticks ( '`' symbol ) or $(cmd) bash sytax to substitute cmd output
java do not understand unix- (cygwin-) style paths, only windows-style.
And at last first link in google answers you question
The main cause of the issue is NOT the backtic but instead the issue of colon versus semi-colon. Since in cygwin, the java running there is for DOS/Windows environment it is expecting ';' as the path separator.
While backtic does help, the main root cause of the issue must be emphasize the difference between ':' and ';' when Java is in Unix or in Windows environment.