ProcessBuilder pb = new ProcessBuilder("pwd");
pb.directory(new File("/server1/work/uz/rt/adapt/0/"));
Process s = pb.start();
I expected the output to be /server1/work/uz/rt/adapt/0/, but instead it's:
/work/uz/rt/adapt/0/
/work/uz/rt/adapt/0/ and /server1/work/uz/rt/adapt/0/ are equivalent (mounted at the same place,/work/.. is correct path and /server1/work/.. is the mounted one ), but I need to work under /server1/work/uz/rt/adapt/0/ because some other servers only work through that path.
How can I make /server1/work/uz/rt/adapt/0/ the current path?
IN OTHER WORDS
why public ProcessBuilder directory(File directory)
converts directory into canonical File. How can I use absolute File Path??
I also tried the hack soln'
pb.directory(new File("/asr1/work/oguz/rt/adaptMLLR2/0/"){
public File getCanonicalFile(){
return this.getAbsoluteFile();
}
public String getCanonicalPath() {
return this.getAbsolutePath();
}
});
which didnt work as well.
I resolved my problem by adding cd /server1/.. line in to the bash script.. and deleted pd.directory(..) line. BUT this problem (why I cant use pd.directory(..) with absolutePath ) is not answered yet...???
Using a shell's cd utility seems an appropriate solution. An alternative would be to set the PWD environment variable to the pathname with symlinks, but this is ugly unless you get ProcessBuilder to do it for you automatically.
Note that shells ignore PWD if it is not an absolute pathname for the current directory, asking the system for a absolute pathname without symlinks instead.
Related
I am trying to jar all the files in a folder with the jar command using Java as follows,
jar -cvf /Abhishek/logs.jar my_directory/logs/*.logs*
I am using Java to execute this.
String cmd[] = {"jar", "-cvf", "/Abhishek/logs.jar", "my_directory/logs/*.logs*"};
pb = Runtime.getRuntime().exec(cmd);
but only the manifest is getting stored in the jar.
added manifest
When I extract the jar file, I am getting the manifest file.
So I had a doubt regarding
*log.*
Is this type of syntax allowed to be used?
Cause it worked fine in the terminal.
Could someone shed some light into this?
Thank you.
On Linux, file globbing is done by the shell. So when you enter *.log at the terminal, the shell will expand it to the list of matching files. Which is then passed to the program.
If you execute the program directly, you would have to expand the pattern yourself. Or you could let the shell execute it with a command similar to
String cmd[] = {"sh", "-c", "jar -cvf /Abhishek/logs.jar my_directory/logs/*.logs*"};
You may want to just use the same classes in the java.util.jar package that the jar command uses. This will avoid a second Java process and will avoid relying on shell expansion:
try (JarOutputStream jar = new JarOutputStream(
new BufferedOutputStream(
Files.newOutputStream(
Paths.get("/Abhishek/logs.jar"))));
DirectoryStream<Path> dir = Files.newDirectoryStream(
Paths.get("my_directory/logs"), "*.logs*")) {
for (Path file : dir) {
BasicFileAttributes attr =
Files.readAttributes(file, BasicFileAttributes.class);
String name = file.toString();
if (attr.isDirectory()) {
name = name + "/";
}
JarEntry entry = new JarEntry(name);
entry.setLastModifiedTime(attr.lastModifiedTime());
entry.setLastAccessTime(attr.lastAccessTime());
entry.setCreationTime(attr.creationTime());
entry.setSize(attr.size());
jar.putNextEntry(entry);
Files.copy(file, jar);
}
}
I would like to use the rar.exe path in Java. This is needed to unpack rar files from within my Java application without using a library.
I figured I'd require the user to add the program files folder for Winrar to the PATH system variable.
All I need to know now is how to get the full path to the rar.exe file.
What I've got now is this:
//Split all paths
String[] paths = System.getenv("Path").split(";");
for(String value : paths)
{
if(value.endsWith("Winrar"))
System.out.println(value);
}
However, there is no way of me knowing if the user installed Winrar to say C:\Programfiles\Winrarstuff. Is there a way to get the location of rar.exe, or do I have to manually scan every folder in the Path string for the location?
You can use where on Windows Server 2003+ which is roughly equivalent to which in *nix, however you can get similar behavior for other windows environments using the code found here: https://stackoverflow.com/a/304441/1427161
When the path to rar.exe is in the PATH environment variable, you can simply invoke rar.exe from any file location. That means you can also call it via Runtime.exec(...). If the return code is other than 0, the process cannot be started, e.g. because Winrar is not installed:
public static boolean checkRar() {
Process proc = Runtime.getRuntime().exec("cmd /c rar.exe");
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
// parse line e.g. to get version number
}
}
return (proc.waitFor() == 0);
}
I'm trying to use the Java function Runetime.exec(String) to run a program in the startup folder of a windows 7 computer like so:
Runtime.getRuntime().exec(runner.getPath() + "\\run.bat");
And when I run this I get an error saying the command cannot be run:
Exception in thread "main" java.io.IOException: Cannot run program ""C:\Users\ly
ndsey\AppData\Roaming\Microsoft\Windows\Start": CreateProcess error=2, The syste
m cannot find the file specified
As you can see, the file name is cut off at the "\Windows\Start" when it should continue to "\Windows\Startup\run.bat".. Is there an alternative I can use?
Considering runner as a File instance, this should work.
Desktop.getDesktop().open(new File(runner, "run.bat"));
It uses Desktop class instead of Runtime, so you don't have to convert your File (runner) to its String representation (which is error prone). Runner is now used 'as is' as the parent directory of the "run.bat" you want to execute.
Other advantage of Desktop class : you can now open any file you want.
As an alternative you can use ProcessBuilder. I feel ProcessBuilder is more safe than Runtime.getRuntime().exec http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
String[] command = {"CMD", "/C", "dir"};
ProcessBuilder pb = new ProcessBuilder( command );
//set up your work directory if needed
pb.directory(new File("c:\\path"));
Process process = pb.start();
as i can see from the error you give, and i hope it's a copy past, you string runner.getPath() for some reason start and end with "\"" which make the whole path invalid. check that and remove it if needed
if you have the file already and you just need it's path you can use
runner.getAbsolutePath()
also, if runner is a file, getPath will give you the file path including the path, so your code will surely won't work. instead use:
String path = runner.getPath();
path = path.substring(0, path.lastIndexOf("\\")) + "\\run.bat";
Runtime.getRuntime().exec(path);
You should avoid the exec(String) method, which attempts to parse the entire string into command + arguments. The safe option is exec(String[]), which presupposes the first array element is the command and the rest are arguments.
So, writing
Runtime.getRuntime.exec(new String[] { yourCommandString })
is a surefire way of getting the right message across.
I am running shell scripts with the help of java and cygwin. When i am running my code in windows xp it works fine. Now i am trying to run same code on windows 7 i am getting above error.
(java.io.IOException)java.io.IOException:
Cannot run program "sh" (in directory"c:\cygwin\bin\test"):
CreateProcess error=2.The system cannot find file specified
Why this error occurred.I have set my path for cygwin (PATH=.;c:\cygwin\bin) How to avoid this.
ProcessBuilder pb = new ProcessBuilder ();
pb.directory(new File("C:\\cygwin\\bin\\Test\\"));
File shellfile = new File("app.sh");//File name with extension
System.out.println(shellfile.getCanonicalPath());
But it is giving the output as E:\NIRAJ\example\app.sh which is in my java program. even i am setting up pb.directory to the path.
if i check System.out.print(pb.directory()); it gives me output C:\cygwin\bin\Test
In PATH variable, you need to put cygwin's bin directory before any other Windows' paths.
Do this:
PATH=c:\cygwin\bin:RestWindowsPaths
Not that:
PATH=RestWindowsPathVariables:c:\cygwin\bin
First try to get the path of specified file first to ensure it:
I am not much sure but this may lead you one step ahead :
File file = new File("app.sh");//File name with extension
System.out.println(file.getCanonicalPath());
This should print : c:\cygwin\bin\test
Also use separator like this instead : c:\\cygwin\\bin\\test
Hope this helps.
UPDATE
String myCommand = "c:\\cygwin\\bin\\test\\cygbin";
String myArg = PATH_TO_shellscript+"app.sh";
ProcessBuilder p = new ProcessBuilder(myCommand, myArg).start();
How do I find the home directory of an arbitrary user from within Grails? On Linux it's often /home/user. However, on some OS's, like OpenSolaris for example, the path is /export/home/user.
Normally you use the statement
String userHome = System.getProperty( "user.home" );
to get the home directory of the user on any platform. See the method documentation for getProperty to see what else you can get.
There may be access problems you might want to avoid by using this workaround (Using a security policy file)
For UNIX-Like systems you might want to execute "echo ~username" using the shell (so use Runtime.exec() to run {"/bin/sh", "-c", "echo ~username"}).
Try this on Java:
System.out.println("OS: " + System.getProperty("os.name") + ", USER DIRECTORY: " + System.getProperty("user.home"));
For an arbitrary user, as the webserver:
private String getUserHome(String userName) throws IOException{
return new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo ~" + userName}).getInputStream())).readLine();
}
You can use the environment variable $HOME for that.
If you want to find a specific user's home directory, I don't believe you can do it directly.
When I've needed to do this before from Java I had to write some JNI native code that wrapped the UNIX getpwXXX() family of calls.
I assume you want to find the home directory of a DIFFERENT user. Obviously getting the "user.home" property would be the easiest way to get the current user home directory.
To get an arbitrary user home directory, it takes a bit of finesse with the command line:
String[] command = {"/bin/sh", "-c", "echo ~root"}; //substitute desired username
Process outsideProcess = rt.exec(command);
outsideProcess.waitFor();
String tempResult;
StringBuilder sb = new StringBuilder();
while((tempResult = br.readLine()) != null) sb.append(tempResult);
br.close();
return sb.toString().trim();
Now technically, we should have a thread waiting on the stdout and stderr so the buffers don't fill up and lock up the process, but I'd sure hope the buffer could at least hold a single username. Also, you might want to check the result to see if it starts with ~root (or whatever username you used) just to make sure the user does exist and it evaluated correctly.
Hope that helps. Vote for this answer if it does as I'm new to contributing to SO and could use the points.
If your are trying to do this for a user name that you cannot hard code, it can be challenging. Sure echo ~rbronosky would tell you the path to my home dir /home/rbronosky, but what if rbronosky is in a variable? If you do name=rbronosky; echo ~$name you get ~rbronosky
Here is a real world case and the solution:
You have a script that the user has to run via sudo. The script has to access the user's home folder. You can't reference ~/.ssh or else it will expand to /root/.ssh. Instead you do:
# Up near the top of your script add
export HOME=$(bash <<< "echo ~${SUDO_USER:-}")
# Then you can use $HOME like you would expect
cat rsa_key.pub >> $HOME/.ssh/authorized_keys
The beauty of it is that if the script is not run as sudo then $SUDO_USER is empty, so it's basically the same thing as doing "echo ~". It still works as you' expect.
If you use set -o nounset, which you should be using, the variable reference ${SUDO_USER:-} will default to blank, where $SUDO_USER or ${SUDO_USER} would give an error (because it is unset) if not run via sudo.
eval echo ~$SUDO_USER
might work.
To find the home directory for user FOO on a UNIX-ish system, use ~FOO. For the current user, use ~.
Can you parse /etc/passwd?
e.g.:
cat /etc/passwd | awk -F: '{printf "User %s Home %s\n", $1, $6}'
Find a Java wrapper for getpwuid/getpwnam(3) functions, they ask the system for user information by uid or by login name and you get back all info including the default home directory.
The userdir prefix (e.g., '/home' or '/export/home') could be a configuration item. Then the app can append the arbitrary user name to that path.
Caveat: This doesn't intelligently interact with the OS, so you'd be out of luck if it were a Windows system with userdirs on different drives, or on Unix with a home dir layout like /home/f/foo, /home/b/bar.