6

Original post the one that most people were answering

Here is the code I have already tried doing this with

String workingDirectory = "/home";
String command = "cd ../";

ProcessBuilder pb = new ProcessBuilder(new String[] { "cmd", "/c", command });
pb.directory(new File(workingDirectory));
pb.redirectErrorStream(true);
Process process = pb.start();

// Some time later once the process has been closed
workingDirectory = pb.directory().getAbsolutePath();
System.out.println("Path: " + workingDirectory);

This does not work, once it finishes it comes out with the same working directory.

Any help would be greatly appreciated, this would be a very useful think to know.

To be more specific, I am looking to find the working directory of a dynamically created process in Java, such as in the snippet above. This is important because such as the predefined command above, working directories can change sometimes, I would like to save any changes into memory for later use.

I found a way to do this, and it seems to work problem free

Here is how I am handling the incoming working directory

public int osType = 1; // This is for Windows (0 is for Linux)

public boolean isValidPath(String path) {
    try {
        Paths.get(new File(path).getAbsolutePath());
    } catch (InvalidPathException | NullPointerException ex) {
        return false;
    }
    return true;
}

public String tracePath(String path) {
    try {
        if (!path.contains("%%") && !isValidPath(path)) return null;
        if (path.contains("%%")) path = path.substring(path.indexOf("%%"));
        int lastIndex = -1;
        char filesystemSlash = ' ';
        if (osType == 0)
            filesystemSlash = '/';
        if (osType == 1)
            filesystemSlash = '\\';
        if (osType == 0)
            path = path.substring(path.indexOf(filesystemSlash));
        if (osType == 1)
            path = path.substring(path.indexOf(filesystemSlash) - 2);
        String tmp = path;
        boolean broken = true;
        while (!isValidPath(tmp)) {
            int index = tmp.lastIndexOf(filesystemSlash);
            if (lastIndex == index) {
                broken = false;
                break;
            }
            tmp = tmp.substring(0, index);
            lastIndex = index;
        }
        if (broken && lastIndex != -1) {
            tmp = path.substring(0, lastIndex);
        }
        return tmp;
    } catch (StringIndexOutOfBoundsException ex) {
        return null;
    }
}

Here is the method of ignoring issues with the path (by not using it)

public boolean setDirectory(ProcessBuilder pb, String path) {
    try {
        pb.directory(new File(new File(path).getAbsolutePath()));
        return true;
    } catch (Exception ex) {
        return false;
    }
}

Now here is how I am starting the process for Windows or Linux

File file = null;
        if (osType == 1) {
            ProcessBuilder pb = new ProcessBuilder(new String[] { "cmd", "/c", command + " & echo %% & cd" });
            pb.redirectErrorStream(true);
            if (!workingDirectory.equals(""))
                setDirectory(pb, workingDirectory);
            process = pb.start();
        } else if (osType == 0) {
            file = new File("script.sh");
            FileWriter writer = new FileWriter(file, false);
            writer.append(command + " && echo %% && pwd");
            writer.flush();
            writer.close();
            ProcessBuilder pb = new ProcessBuilder(new String[] { "bash", System.getProperty("user.dir") + "/script.sh" });
            pb.redirectErrorStream(true);
            if (!workingDirectory.equals(""))
                setDirectory(pb, workingDirectory);
            process = pb.start();
        } else
            return;

Finally here is the loop that manages the process and the working directory

while (process.isAlive() || process.getInputStream().available() > 0) {
            byte[] returnBytes = new byte[1024];
            process.getInputStream().read(returnBytes);
            char[] arr = new String(returnBytes).trim().toCharArray();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < arr.length; i++) {
                char c = arr[i];
                if (Character.isDefined(c))
                    sb.append(c);
            }
            String response = sb.toString();
            if (!response.equals("")) {
                String path = tracePath(response.trim().replace("\n", "").replace("\r", ""));
                if (path != null && osType == 1) {
                    if (Paths.get(path).toFile().exists())
                        workingDirectory = path;
                } else if (path != null && osType == 0) {
                    if (Paths.get(path).toFile().exists())
                        workingDirectory = path;
                }
                client.sendMessage(response + '\r' + '\n');
            }
        }
if (file != null) file.delete();

Here is the output from the command receiving website

Connecting..
Connected.
Success. You have been connected -> Speentie

bash -c pwd
/root/hardsceneServer/remoteServer

%%
/root/hardsceneServer/remoteServer

bash -c cd ..

%%
/root/hardsceneServer

bash -c pwd
/root/hardsceneServer

%%
/root/hardsceneServer

bash -c dir
ircServer  nohup.out  remoteServer  start.sh  start1.sh  start2.sh

%%
/root/hardsceneServer

bash -c cd ircServer

%%
/root/hardsceneServer/ircServer

bash -c dir
HardScene.jar         hardscene_banned.properties  start.sh
hardscene.properties  nohup.out

%%
/root/hardsceneServer/ircServer
  • what is command here? – Wasi Ahmad Mar 04 '17 at 16:48
  • If you're asking how to retrieve the working directory of another process, then that's not possible. – Andreas Mar 04 '17 at 16:51
  • How is it not possible when Linux can do it? I thought Java can also interface with the machine? There has to be a way, even if it is extremely complicated. –  Mar 04 '17 at 16:59
  • What workingDirectory are you looking for? The one used by the jvm? – bichito Mar 04 '17 at 17:11
  • No.. the absolute directory of a dynamically started process from Java –  Mar 04 '17 at 18:04
  • 1
    what exactly are you trying to do and why? Understanding this might help us come up with a better solution – Brian Pipa Mar 07 '17 at 19:35
  • @BrianPipa "To be more specific, I am looking to find the working directory of a dynamically created process in Java, such as in the snippet above." –  Mar 10 '17 at 17:59
  • Think I just thought of something hold on.. Gonna try calling a command to retrieve working directory as something to execute right after the command you typed, and see if I can like store what it returns in memory –  Mar 10 '17 at 18:02
  • Okay yeah what I just did seems to work, but it acts kinda weird. I will put what I did to make it work in the original question. –  Mar 10 '17 at 18:34
  • Updated. The code works so much better now, with complete Linux support also. If anyone is willing to improve upon my code go ahead, it would be greatly appreciated. –  Mar 11 '17 at 02:09
  • This is really ugly and not a solution but a hack. – kriegaex Mar 11 '17 at 13:37

7 Answers7

3

Are you looking for something like this?

System.out.println("Current working directory: " + System.getProperty("user.dir"));
System.out.println("Changing working directory...");
// changing the current working directory
System.setProperty("user.dir", System.getProperty("user.dir") + "/test/");

// print the new working directory path
System.out.println("Current working directory: " + System.getProperty("user.dir"));

// create a new file in the current working directory
File file = new File(System.getProperty("user.dir"), "test.txt");

if (file.createNewFile()) {
    System.out.println("File is created at " + file.getCanonicalPath());
} else {
    System.out.println("File already exists.");
}

It outputs:

Current working directory: /Users/Wasi/NetBeansProjects/TestProject
Changing working directory...
Current working directory: /Users/Wasi/NetBeansProjects/TestProject/test/
File is created at /Users/Wasi/NetBeansProjects/TestProject/test/test.txt
Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
  • Not really, you almost got it, you see when people execute something "cd ../" into the command window, it does it for that one command, but it doesn't save that new directory into memory in Java because of course that is stored in an entirely new process. So all I need is some way to pass a process in and get a working directory of that process out, so that it can be reused later. –  Mar 04 '17 at 18:05
  • @SkorrloreGaming I got you. but why don't you use `System.getProperty("user.dir")`? Do you want to save the current working directory for a process only? – Wasi Ahmad Mar 04 '17 at 18:15
  • I want specifically the working directory of the dynamic process nothing else –  Mar 04 '17 at 18:17
2

I am looking to find the working directory of a dynamically created process in Java,

You can certainly lookup the working directory of the current Java process by looking at the value of the user.dir system property:

String cwd = System.getProperty("user.dir");

But finding out the working directory of another process is not possible unless you are using special OS calls. On Linux, if you know the pid then you can look at /proc/[pid]/cwd but there is no easy equivalent in OSX or Windows that I know about.

This does not work, once it finishes it comes out with the same working directory.

Yeah, you are not able to issue a command to change the working directory because once the cmd exits, the working directory will be reset.

According to this page, you can set the working directory by assigning the user.dir system property:

System.setProperty("user.dir", "/tmp");

However this may be OS dependent and doesn't work on my OSX box. For example, the following code creates the x1 and x2 files in the same directory:

new File("x1").createNewFile();
// this doesn't seem to do anything
System.setProperty("user.dir", "/tmp");
new File("x2").createNewFile();

This answer says that there is no reliable way to do this in Java. I've always taken the opinion that you can't change the working directory and that you should be specific with new File(parent, filename) to show where files live, etc..

Community
  • 1
  • 1
Gray
  • 115,027
  • 24
  • 293
  • 354
1

It cannot be achieved in Java by ProcessBuilder's directory() method because it sets the working directory of a process, not where the binary is. You have to do it in another level.

If you are working with GNU/Linux, whereis and update-alternative are your best bet. In Windows, you have where. Now, it comes to the usage of commands in different OS, and the parsing of the outputs. It may be hard.

Some pseudo code to begin with:

  1. execute whereis plus the command as parameter, with ProcessBuilder
  2. try to parse the output. You may deal with multiple line output.

Or,

  1. execute update-alternatives plus the command as parameter, with ProcessBuilder
  2. try to parse the output. There may be several alternatives for one command, such as for java, you may have some different JDKs installed.
  3. Or, list all links in /var/libs/alternatives and find what you want, maybe with pipe. You can see here:

https://serverfault.com/questions/484896/is-there-a-way-to-list-all-configurable-alternatives-symlinks-for-similar-com

But, I still doubt why you are doing this. So, if you can clarify the original requirements, it would help a lot. It's for avoiding X-Y problem.

Community
  • 1
  • 1
WesternGun
  • 11,303
  • 6
  • 88
  • 157
  • +1 This is useful for Linux users, but in testing this does not work as expected. I am looking for a Windows and Linux solution for the project, though this is not one. Thankfully, though, I found a solution on my own in time of release. –  Mar 14 '17 at 15:45
  • So, after all what was your solution? It interests me. – WesternGun Mar 15 '17 at 14:16
  • I posted the most updated code I am using as an edit to the question. –  Mar 15 '17 at 14:49
0

What you can do is to use handle from sysinternals for windows

https://technet.microsoft.com/en-us/sysinternals/bb896655.aspx

or

ls -l /proc/[PID]/fd or pfiles [PID] for linux

and find a folder that was last used by that process.

String commandToGetOpenFiles="handle... or ls...";
BufferedReader reader = new BufferedReader(
        new InputStreamReader(Runtime.getRuntime()
                .exec(commandToGetOpenFiles).getInputStream()));

and to start you process and get PID use wmic process call create "cmd"

Sash
  • 11
  • 5
0

Use this to get the URL of your current file directory:

URL url = ClassLoader.getSystemResource(FileName);

It works anywhere. Not just your PC, even in cloud.

It returns an URL(java.net) type. For ClassLoader, you don't need to import anything.

In the FileName, use any filename you want to get the path for.

Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
cruck
  • 5
  • 2
0

Your question is unclear a bit, but if you're trying to find the current directory from WITHIN the current process, just do

new File("").getAbsoluteFile().getAbsolutePath();
-1

use the below code

Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
System.out.println("Current relative path is: " + s);
Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
abhishek sahu
  • 648
  • 4
  • 8