I want to execute a batch file within my java application.
I want to execute it this way:
String[] args = new String[] {
"C:/Users/User1/Desktop/Bachelor Thesis/JDBC Connector/jdbc_5.2_sp1_patch05/bin/connect.bat",
"start",
"-f",
"C:/Users/User1/Content-Integration Testing Framework/JDBC Connector/etc/db.xml" };
Process p = Runtime.getRuntime().exec(args);
p.waitFor();
BufferedReader prout = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String buffer;
while ((buffer = prout.readLine()) != null) {
System.out.println(buffer);
buffer = prout.readLine();
}
For explaination:
Let us consider I would use a normal cmd execution. I would open cmd, then i would go to my directory:
cd C:/Users/User1/Desktop/Bachelor Thesis/JDBC Connector/jdbc_5.2_sp1_patch05/bin
Afterwars I would start the batch file with the following command:
connect start -f C:/Users/User1/Content-Integration Testing Framework/JDBC Connector/etc/db.xml
On the command line this works fine, it starts the batch and inside this batch there is a subprocess wich gets started:
if exist %JAVA_HOME%\bin\java.exe (
java -XX:NewSize=%NEWSIZE% -XX:NewRatio=1 -Xms%MAXHEAP% -Xmx%MAXHEAP% -Dfile.encoding=%ENCODING% -Djava.ext.dirs=%EXT_DIR% com.fastsearch.esp.connectors.jdbc.JDBCConnector %1 %2 %3 %4 %5 %6 %7
) else (echo Is JAVA_HOME=%JAVA_HOME% set correctly?)
But with my execution inside my Java application I have the following problem:
It only prints the first echo of my batch file but the subprocess does not start. When I catch the errorstream (like shown in the code on top) it says:
UNC-Pfade werden nicht unterstützt. (UNC-Paths are not supported)
java.lang.NoClassDefFoundError: com/fastsearch/esp/connectors/jdbc/JDBCConnector
After some reseach I found out that the cmd has problems to start subprocesses because of the current working directory or something like that. I did not really understand that.
The actual thing is, that I want to execute the batch file with its neccesary parameters (start, -f and the path) within my Java application. When I execute the statements directly on the cmd everything works fine but inside my java application it sucks.
Here is the full batch file, maybe this is helpful:
#echo off
rem This bat file should setup the java env and run the connector manager
SETLOCAL
echo Copyright (c) Microsoft Corporation. All rights reserved.
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
rem Java 1.6 must be installed and set here
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if NOT defined JAVA_HOME (
echo Sorry..
echo You have NOT set JAVA_HOME - Should point to where JRE 1.6.x or later is installed
echo Exiting.......
goto end
)
set JAVA_HOME=%JAVA_HOME%
:: Remove quotes if exist, then add quotes in case spaces
SET JAVA_HOME=###%JAVA_HOME%###
SET JAVA_HOME=%JAVA_HOME:"###=%
SET JAVA_HOME=%JAVA_HOME:###"=%
SET JAVA_HOME=%JAVA_HOME:###=%
SET JAVA_HOME="%JAVA_HOME%"
SET PATH=%JAVA_HOME%\bin
SET EXT_DIR=..\lib;%JAVA_HOME%\lib;%JAVA_HOME%\lib\ext
SET CLASSPATH=..\etc
SET MAXHEAP=1408m
SET NEWSIZE=256m
SET ENCODING=UTF8
if exist %JAVA_HOME%\bin\java.exe (
java -XX:NewSize=%NEWSIZE% -XX:NewRatio=1 -Xms%MAXHEAP% -Xmx%MAXHEAP% -Dfile.encoding=%ENCODING% -Djava.ext.dirs=%EXT_DIR% com.fastsearch.esp.connectors.jdbc.JDBCConnector %1 %2 %3 %4 %5 %6 %7
) else (echo Is JAVA_HOME=%JAVA_HOME% set correctly?)
:end
As you touched on, it is highly likely that your problem is that you are not executing the batch file from the proper directory. When you open the command line console and cd into the directory containing the batch file, THAT action sets the proper current working directory (CWD).
You can resolve it by changing the CWD before, or after, you enter your batch file.
Let's start by working with the CWD in the batch file; we've got a number of options here also, but let's keep it simple and just change the CWD:
set MYDIR=%~dp0
cd %MYDIR%
The first line uses a bit of batch-file magic to obtain the directory in which the currently executing batch file lives. That would be "C:/Users/User1/Desktop/Bachelor Thesis/JDBC Connector/jdbc_5.2_sp1_patch05/bin/"
Alternative
You could use an alternate form of the Runtime.getRuntime().exec() to change the CWD:
Runtime.getRuntime().exec(String[] cmdarray, String[] envp, File dir)
Invoke as:
File workingDir = new File("C:/Users/User1/Desktop/Bachelor Thesis/JDBC Connector/jdbc_5.2_sp1_patch05/bin/");
Runtime.getRuntime().exec(args, null, workingDir);
I'd strongly suggest you declare a static final const value for your working dir, or find some way to eliminate the hard-coding of that value in your program.
I would like to write down the correct answer now as a summary. But I have to mention that this is the idea of Richard Sitze and not mine.
static final String workingdirectory = "C:/Users/User1/Desktop/Bachelor Thesis/JDBC Connector/jdbc_5.2_sp1_patch05/bin";
String[] args = new String[] {"C:/Users/User1/Desktop/Bachelor Thesis/JDBC Connector/jdbc_5.2_sp1_patch05/bin/connect.bat",
"start",
"-f",
"C:/Users/User1/Content-Integration Testing Framework/JDBC Connector/etc/db.xml" };
Process p = Runtime.getRuntime().exec(args2, null, workingDir);
BufferedReader prout = new BufferedReader(new InputStreamReader(p.getInputStream()));
String buffer;
while ((buffer = prout.readLine()) != null) {
System.out.println(buffer);
buffer = prout.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
Related
I'm trying to run a java command in cmd using C# to get some inputs for my program, the path for Java is set correctly, and I am able to run Java commands in the cmd without any trouble but when I tried it in C#, it's showing " 'java' is not recognized as an internal or external command, operable program or batch file. " as if the path is not set.
But I am able to run the same command outside, don't know what seems to be the issue, kindly help, thanks in advance!
string cmd = #"/c java -jar """ + $"{treeEditDistanceDataFolder}libs" + $#"\RTED_v1.1.jar"" -f ""{f1}"" ""{f2}"" -c 1 1 1 -s heavy --switch -m";
Console.WriteLine(cmd);
var proc = new Process();
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = cmd;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.Start();
Console.WriteLine("Process started");
string output = proc.StandardOutput.ReadToEnd();
Console.WriteLine("Output was read");
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
This line is your problem:
proc.StartInfo.UseShellExecute = false;
When UseShellExecute is true, the system and user PATH variables will be used if the application to launch is just the executable name. Because you're setting it to false, and java doesn't exist in your application's folder, it isn't possible for .NET to find it.
You have two options:
Set UseShellExecute to true so that it can use the PATH variable to find java.
Use a fully qualified path, e.g. "C:\Program Files\Java\jdk1.8.0_101\bin\java"
See this answer for more info.
I unable to copy the zip content from one windows system (eg: cat300) to another windows system (cat400) using the below code.
PROBLEM is "fullRegFolder" contains "Test.zip" which is in (cat300 machine) and which I need to move to "radbatDir" which is in another
windows system.
My configuration.xml shows as below:
<AutomationTestServer>
<!--Destination and credentials for where the automation testing should be done -->
<Host>cat200</Host>
<User>test</User>
<Password>xx</Password>
<JavaHome>C:/abc/Web/AppServer/java</JavaHome>
<RadBatInterface>C:/Rad/UT2122/RadBatInterface</RadBatInterface>
</AutomationTestServer>
In my java code calling as below
String fullRegFolder = PropertyHolder.getProperty ("SmokeCompletetTestFolder");
// Lets copy the file to the Server.
String radBatDir=PropertyHolder.getProperty("AutomationTestServer.RadInterface");
radBatDir = radBatDir.replace('/', '\\');
fullRegFolder = fullRegressionFolder.replace('/', '\\');
pr = rt.exec("copyTestToWindows.cmd "+fullRegFolder+"\\Test.zip " + radBatDir);
input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
line=null;
while((line=input.readLine()) != null) {
logger.debug(line);
}
exitVal = pr.waitFor();
logger.info("Copy to Server completed with exit code "+exitVal);
copyTestWindows.cmd:
#echo off
#echo Copying Test Content to Server
IF NOT EXIST %1 GOTO testContentNotExist
IF NOT EXIST %2 GOTO radBatDirNotExist
copy /Y %1 %2
goto success
:testContentNotExist
#echo The test content %1 does not exist
exit 2
:radBatDirNotExist
#echo The rad Bat Directory %2 does not exist
exit 2
:success
#echo The test content %1 successfully copied to dir %2
Please help on this:
error shows : radBatDir does not exist
#echo off
if "%1" == "" (
echo "Usage: <outputDirectory>"
) else (
if not exist "abc\cdf" mkdir abc\cdf
if not exist "xyz" mkdir xyz
if not exist "xyz\mno" mkdir xyz\mno
xcopy export xyz\mno /e
set xyz_JAR=xyz.jar
set xyz_JAR_PATH=..\app\build\libs\
set FILES=mno "%xyz_JAR%"
copy "%xyz_JAR_PATH%%xyz_JAR%" xyz
//copy ..\app\build\libs\xyz.jar xyz
set ZIP_FILE=xyz_v0-8-0_export.zip
if exist "xyz\mno\.zip" del xyz\mno\.zip
cd "xyz"
echo '%cd%'
zip -r %ZIP_FILE% %FILES%
del %xyz_JAR%
echo y | del mno\config\*.*
rmdir mno\config
rmdir mno\out
echo y | del /s mno\
rmdir mno
move %ZIP_FILE% ..\%1\%ZIP_FILE%
cd ..
rmdir xyz
)
Here is my .bat file which is being executed perfectly from command line. I would like to run the same from java where I am seeing issues at various stages
String command = "packageEGRC_export.bat"+" "+"exportEGRC";
Process process = Runtime.getRuntime().exec(new String[] {"cmd.exe","/c",command},null,scriptDir);
InputStream is = process.getInputStream();
int i = 0;
while( (i = is.read() ) != -1) {
System.out.print((char)i);
}
process.waitFor();
int exitValue = process.exitValue();
It is picking up bat file and executing till certain stage and failing at line
copy "%xyz_JAR_PATH%%xyz_JAR%" xyz
Saying not able to find the file path. But if I replace that with, it's working fine
copy ..\app\build\libs\xyz.jar xyz
And next not able to change directory to xyz --> cd "xyz", it remains same working directory where it is being executed.
Any help on this would be appreciated.
Note: I don't want to change anything on .bat file because it is working perfectly from command line.
Looks like problem is in .bat file itself: you set variable in if statement, but statement has to be read completely (compound expression) before execution. It is where variables are substituted. When you execute your script with Java, you have no environment variables set yet so expression
cd "%var%"
is populated with empty string hence Could not find error pops.
If you rewrite your code to set variables before entering if it will work.
Also you observe script work when called from command line because these variables were already set after first invocation of script. Simply check if your original script works after in freshly opened cmd.exe. Your script should fail.
Here is an example:
#echo off
if "%1" == "" (
set xyz_JAR=xyz.jar
set xyz_JAR_PATH=..\bat\
echo "%xyz_JAR_PATH%%xyz_JAR%"
)
And invocation:
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
D:\tmp\bat>test.bat
""
D:\tmp\bat>test.bat
"..\bat\xyz.jar"
D:\tmp\bat>
1) Use absolute paths
2) dont cd, use pushd to change directory and popd to change back
I don't know about this method , but I have a idea how to run a bat file in Java
Runtime runtime = Runtime.getRuntime();
try {
Process p1 = runtime.exec("cmd /c start D:\\temp\\a.bat");
InputStream is = p1.getInputStream();
int i = 0;
while( (i = is.read() ) != -1) {
System.out.print((char)i);
}
} catch(IOException ioException) {
System.out.println(ioException.getMessage() );
}
/C Carries out the command specified by the string and then terminates.
to your answer yer there are many
go to your command window and C:\>cmd /? you will get below list
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
/S Modifies the treatment of string after /C or /K (see below)
/Q Turns echo off
/D Disable execution of AutoRun commands from registry (see below)
/A Causes the output of internal commands to a pipe or file to be ANSI
/U Causes the output of internal commands to a pipe or file to be
Unicode
/T:fg Sets the foreground/background colors (see COLOR /? for more info)
/E:ON Enable command extensions (see below)
/E:OFF Disable command extensions (see below)
/F:ON Enable file and directory name completion characters (see below)
/F:OFF Disable file and directory name completion characters (see below)
/V:ON Enable delayed environment variable expansion using ! as the
delimiter. For example, /V:ON would allow !var! to expand the
variable var at execution time. The var syntax expands variables
at input time, which is quite a different thing when inside of a FOR
loop.
/V:OFF Disable delayed environment expansion.
I need to run an .sh file and get its output. I need to see the setup of the file as well.
The .sh file simply runs a java app through terminal.
Any ideas? I'm truly stuck on this.....
Elijah
The server.sh file:
echo Starting Jarvis Program D.
ALICE_HOME=.
SERVLET_LIB=lib/servlet.jar
ALICE_LIB=lib/aliceserver.jar
JS_LIB=lib/js.jar
# Set SQL_LIB to the location of your database driver.
SQL_LIB=lib/mysql_comp.jar
# These are for Jetty; you will want to change these if you are using a different http server.
HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar
PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1
My current code:
NSTask *server = [NSTask new];
[server setLaunchPath:#"/bin/sh"];
[server setArguments:[NSArray arrayWithObject:#"/applications/jarvis/brain/server.sh"]];
NSPipe *outputPipe = [NSPipe pipe];
[server setStandardInput:[NSPipe pipe]];
[server setStandardOutput:outputPipe];
[server launch];
NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:#"Jarvis>"].location == NSNotFound) {
[outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]];
NSRunAlertPanel(#"", outputString, #"", #"", #"");
}
The NSRunAlertPanel is just for checking the output. Now my code is freezing and not even getting to the alertpanel.
See answer to this question.
There are a couple of things that should be fixed in your script:
The script should begin with a
shebang. Also make sure that the
script has its executable bit set.
Because the environment variables are set up relative to the shell script directory, you need to make sure that the script directory is the current directory.
You need to export the environment variables that should be visible to the Java process.
In the last line you can use exec to replace the shell process with the Java executable that runs Jetty.
Here is a revised version of your script:
#!/bin/sh
echo Starting Jarvis Program D.
cd "`dirname \"$0\"`"
export ALICE_HOME=.
export SERVLET_LIB=lib/servlet.jar
export ALICE_LIB=lib/aliceserver.jar
export JS_LIB=lib/js.jar
# Set SQL_LIB to the location of your database driver.
export SQL_LIB=lib/mysql_comp.jar
# These are for Jetty; you will want to change these if you are using a different http server.
export HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar
export PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
exec java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1
Invoking the shell script in Objective-C with multiple arguments:
NSTask *server = [NSTask new];
[server setLaunchPath:#"/bin/sh"];
[server setArguments:[NSArray arrayWithObjects:#"/applications/jarvis/brain/server.sh", #"argument", nil]];
...
Using AMShellWrapperTest.app you can filter (save, ...) the stdout stream of server.sh by modifying "- (void)appendOutput:(NSString *)output" in BannerController.m. (... but maybe there is a better way to do this ...)
/*
// output from stdout
- modified AMShellWrapper/AMShellWrapperTest/BannerController.m (http://www.harmless.de/cocoa-code.php)
to print server.sh setup information to "Error Messages:" text output field (or Console.app as an
alternative) and the Q & A dialog to the "Output:" text field
- use of default charliebot, http://sourceforge.net/projects/charliebot/, modified only to run server.sh
with complete path (here: ~/Desktop/charliebot/server.sh) in AMShellWrapperTest.app
*/
- (void)appendOutput:(NSString *)output
{
NSMutableString *outputString = [NSMutableString string];
if (
([output rangeOfString:#"Charlie>"].location != NSNotFound ) || \
([output rangeOfString:#"[Charlie] user>"].location != NSNotFound )
) {
[self write: output];
[self write: #"\n"];
} else {
[outputString appendString: output];
//[outputString writeToFile:#"/dev/console" atomically: NO]; // alternative
[errorOutlet setString:[[errorOutlet string] stringByAppendingString: outputString]];
}
}
yes, but why isn't my code (posted above) not working?
I guess your "Jarvis>" line is the first line of the server.sh ouput stream that expects some user input, which means that this line is incomplete without a terminating newline character "\n". If server.sh had been run in Terminal.app, the user would have to press the return key to let the dialog continue. The conditional code of the while loop (NSNotFound) cannot finish its job on this incomplete line (which would be to abort the while loop) and gets stuck.
You have to drop the while loop and use the 'readInBackgroundAndNotify' mode on NSFileHandle to get non-blocking I/O stdout stream behaviour!
See: NSTask/NSPipe STDIN hangs on large data, sometimes...
So, if you like, just transform the source code of AMShellWrapperTest.app into a pure command-line tool by removing the GUI code.