Passing a string from Java to a bash script - java

So I have a client and a server Java program. The client uses Java processbuilder to execute the script but my problem is that the user inputs information that needs to be passed to the bash script. So, essentially, I need to know how to send three different strings to three different variables that are being read by the bash script. This script is copying a file so I would rather not make a txt file with java and have the script read the file. I would also like a way for this to be able to run on OS X and Windows so improvements are welcome. I am using Java 7 on Ubuntu currently.
Here is a snippet of what I am trying to do:
.java
Scanner bob = new Scanner(System.in);
String workingDirectory = new String(System.getProperty("user.dir"));
File tempDir = new File(workingDirectory);
String script = new String(workingDirectory + "/copyjava.sh");
System.out.print("Designate the location of the file: ");
String loc = bob.next();
System.out.print("Type the name of the file w/ extension: ");
String name = bob.next();
System.out.print("What is the location of THIS file? "); //I know there is a way to do this automagically but I can't remember how...
String wkspace = bob.next();
ProcessBuilder pb = new ProcessBuilder( script, loc, name, wkspace);
pb.start();
File myFile = new File (name);
Script:
read loc
read name
read wkspace
cd $LOC
cp $name $wkspace

There is a problem with your shell script. The read command reads from stdin, but you are passing the input as arguments. You are also changing the case of the loc variable. Variables in the shell are case sensitive. Change your script to the following:
#!/bin/sh
loc=$1
name=$2
wkspace=$3
cd "$loc" || { printf 'failed to cd to %s\n' "$loc" ; exit 1; }
cp "$name" "$wkspace" || { printf 'failed to copy %s\n' "$name" ; exit 1; }
On a side note, you shouldn't need to call an external script written in a different language just to copy a file. You should implement this in java. Implementing this in java will also give your code the platform independence you desire.

You are passing your args on the command line but reading from stdin in your script. How about changing your script to:
cd $1
cp $2 $3

I don't see any client/server interaction but let's focus on what's really important: Your are passing the parameters to the script but your script is trying to read them from the standard input.
To fix your problem modify your script as follows:
#!/bin/sh
LOC=$1
name=$2
wkspace=$3
cd $LOC
cp $name $wkspace
Take a look at the documentation for more details.
But are not doing anything that would really need a system-specific script file. The best way to copy a file is using the own mechanism that Java provides and then you don't need to worry of the underlying operating system.
If you keep on using the script then you'll need another one for Windows systems and then decide which script you should run based on the value of the os.name system property.

Related

can we use unix variables in our property file in java

In java application I have my properties file which has key/pair values like
usa.national.bank=Bank of America
etc.
Now let's say I deploy my app in a unix box, where I already have variables declared like:
export US_NAT_BANK=Bank of America
SO my app is supposed to run in this unix box and at run time at some point, it will read this value.
So tried declaring my properties file like this:
usa.national.bank=$US_NAT_BANK
but it is not able to read the value defined in variable i.e. "Bank of America", instead it reads the literal value i.e. "$US_NAT_BANK"
AM I doing something wrong or is it not possible to use unix variables in property files?
Java has API to interact with System commands using ProcessBuilder.
You can use following solution to read UNIX properties using java :
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", "echo $US_NAT_BANK");
final Process process = processBuilder.start();
try (InputStream is = process.getInputStream()) {
byte[] result = is.readAllBytes();
System.out.println(new String(result, UTF_8));
}
Using ProcessBuilder you can execute any UNIX supported commands and get same results as you get in console/terminal.
You can more details : ProcessBuilder JavaDoc

Reading file input from Java using terminal

I have a Java file Animal.java, and I want to be able to write a terminal command like so:
java Animal -a -print < data.txt
I know that the -a and -print appear as variables in the array arg (which is an input to the main method -- so arg[0] is -a and arg[1] is -print), but how can I access the data from data.txt?
It's is not possible in java, but instead you may pass the location of the file(not required if its already known and fixed) and then access the file's data using InputStream/ readLine() etc..
You can not manipulate the files in the same way that the Unix pipes do. You need treat your arguments so that there is a prefix or a position that defines the name of the file you want to read, so it is possible read the file passed as argument.
// Treating arguments and verify the possibility of reading file
// Get index which is the file name
FileInputStream fstream = new FileInputStream (argv [FileIndex]);
// Handle the file .
See an example here: Passing a file as a command line argument and reading its lines
Imagina the structure src/mypack/Main.java, run on terminal:
$ cd src/mypack/
/src/mypack$ javac Main.java
/src/mypack$ cd ..
/src$ java mypack.Main < path/your/file

Java: run executable program whit particular parameters

I need to run executable progam (.exe) in java. This program have two different operating modes: GUI and Command line. The syntax to launch the program from the command line is as follows :
C:\Users\Ermanno\Desktop\ "programFolder"\"program.exe" /stext output.txt
in this way the program store the outoput in the file "output.txt".
I tired it:
Process p = new ProcessBuilder("C:\\Users\\Ermanno\\Desktop\\programFolder\\program.exe" ,"/stext a.txt").start();
does not create the output file.
I also tired to use a file batch that contains the command and run it to java but the result is the same.
You need to pass each argument in a single string:
... program.exe", "/stext", "a.txt")...
Also make sure that you start a background thread which reads the output of the child process. If there is a problem, then the child will print an error message to it's standard output and if you don't actively read it, then this output will be lost.
For this, loop over the streams p.getInputStream() and p.getErrorStream().
The latter is especially important since you say "I also tired to use a file batch". Java doesn't do anything different than a batch script. If you can't run the command from batch, it won't work from Java, either.
My experience was horrible with using the JDK ProcessBuilder and Runtime.getRuntime().exec. I then moved to Apache commons-exec. Here is an example:
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);
I solved using file bath. This file contains the command.
String [] _s = {"cmd.exe", "/c", "start", "file.bat"};
Process pr = Runtime.getRuntime().exec(_s);

How to run bat file from java with arguments (i.e file name with full path) having folder name with space

Am trying to execute the a bat file with some arguments through a JAVA programmes . the arguments are file name with full path, And this path had some folder name with space, which are creating issue and giving me the following error
Error: 'D:\Documents' is not recognized as an internal or external
command
the code is as below
String command = "D:\Documents and Settings\ A.bat" + " " D:\Documents and Settings\B.xml
1. process = Runtime.getRuntime().exec(new String[] {"cmd.exe","/c",command});
2. process.waitFor();
3. exitValue = process.exitValue();
You need to escape the \ in your string (i.e. doubling them: D:\\Documents), but that is not the problem. You can try to escape the spaces Documents\\ and\\ Settings or you use the exec method that does this for you. Just dont build the command line by yourself. Better use ProcessBuilder for starting processes.
String command = "\"D:\Documents and Settings\\" A.bat" + " \"D:\Documents and Settings\B.xml\""
Escape double quotes, so you can include double quotes in the literal, to give:
cmd.exe /x "D:\Documents and Settings\" A.bat "D:\Documents and Settings\B.xml"
I was trying to do the same thing. I googled whole day but didn't make it work. At Last I handled it in this way, I am sharing it if it comes to any use of anybody :
String command = "A.bat D:\\Documents and Settings\\B.xml";
File commandDir = new File ( "D:\\Documents and Settings ");
String[] cmdArray = { "cmd.exe", "/c", command };
1. Process process = Runtime.getRuntime().exec( cmdArray, null, cmdArray );
2. process.waitFor();
3. exitValue = process.exitValue();
I've spent a while searching on SO and the wider Internet and was about to post this as a new question when I came across this, which does seem identical to my issue...
I am trying to call a Windows batch file from Java. The batch file takes several arguments but just the first, which is a path to a data file, is of relevance to this problem. The cut-down command line that I have been experimenting with is essentially:
cmd /c c:\path\to\my\batchfile.bat c:\path\to\my\datafile.mdl
I'm using Apache Commons Exec which ultimately delegates to Runtime.getRuntime().exec(String[] cmdarray, String[] envp, File dir), the 'correct' version as opposed to the overloaded versions taking a single String command. Quoting of the arguments when they contain spaces is therefore taken care of.
Now, both the path to the batch file and/or the path to the data file can have spaces in them. If either the path to the batch file or the path to the data file have spaces in, then the batch file is executed. But if both have spaces in them then the path to the batch file is truncated at the first space.
This has to be a (Java or Windows?) bug, right? I've debugged right down to the native call to create() in java.lang.ProcessImpl and all seems ok. I'm on JDK1.6.

Compressing and Archiving the files in the folder using Java Runtime

I am trying to Compress and Archive all the files in a folder, using Java Runtime class. My code snippet looks as this :
public static void compressFileRuntime() throws IOException, InterruptedException {
String date = Util.getDateAsString("yyyy-MM-dd");
Runtime rt = Runtime.getRuntime();
String archivedFile = "myuserData"+date+".tar.bz2";
String command = "tar --remove-files -cjvf "+archivedFile+" marketData*";
File f = new File("/home/amit/Documents/");
Process pr = rt.exec(command, null, f);
System.out.println("Exit value: "+pr.exitValue());
}
The above code doesn't archive and compress the file as expected, though it creates a file myuserData2009-11-18.tar.bz2 in the folder "/home/amit/Documents/".
Also the output is
Exit value: 2.
While if I execute the same command from command line, it gives the expected result.
Please tell me what I am missing.
Thanks
Amit
The problem lies in this part:
" marketData*"
you expect the filenames to be compressed to be globbed from the * wildcard. Globbing is done by the shell, not by the tools themselves. your choices are to either:
numerate the files to be archived yourself
start the shell to perform the command ("/bin/sh -c")
start tar on the folder containing the files to be archived
Edit:
For the shell option, your command would look like:
String command = "sh -c \"tar --remove-files -cjvf "+archivedFile+" marketData*\"";
(mind the \"s that delimit the command to be executed by the shell, don't use single quotes ot the shell won't interpret the glob.)
If really you want to create a bzip2 archive, I'd use a Java implementation instead of a native command which is good for portability, for example the one available at http://www.kohsuke.org/bzip2/ (it is not really optimized though, compression seems to be slower than with Java LZMA).

Categories