Skip to content

Why am I getting IOException : “Cannot run program ./shellScript.sh error = 2, No such file or directory in Java?

The following Main.java code simply tries to simulate the following linux command:

cd /dir1/dir2
./shellScript.sh

The program below works only if the executable Main.jar sits within /dir1/dir2, not outside of /dir1/dir2. How do I modify the program below so that Main.jar can sit anywhere on the file system?

public class Main {

    public static String runCmdLineProcess(String commandStr){
        String returnVal = "";
        Runtime r = Runtime.getRuntime();
        
        try {
            Process p = r.exec(commandStr);
            BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = ""; 
            
            while ((line = b.readLine()) != null){
                returnVal += line + "n";
            }

        }
        catch(IOException ex){
            ex.printStackTrace();
        }
        
        return returnVal;
    }

    public static void runProcessBuilder(String scriptPath){

        String[] cmd = {scriptPath};
        try {
            runCmdLineProcess("cd /dir1/dir2");
            Runtime.getRuntime().exec(cmd);
        }
        catch (IOException ex){
            ex.printStackTrace();
        }
    }
    
    public static void main(String[] args){
        runProcessBuilder("./shellScript.sh"); // <-- works if I run from inside "/dir1/dir2".  
                                               //But if I'm outside "dir2", get an error message 
                                               // saying "Cannot run program "./shellScript.sh": error = 2, No such file or directory
    }

}

Answer

You should use ProcessBuilder to launch or one of the overloads of exec. You need to specify the pathname to the script and pass the same pathname as the current directory to run the script in:

File pwd = new File("/dir1/dir2");
String shell = new File(pwd, "shellScript.sh").toString();

ProcessBuilder pb = new ProcessBuilder(shell);
// No STDERR => merge to STDOUT - or call redirectError(File)
pb.redirectErrorStream(true);
// Set CWD for the script
pb.directory(pwd);

Process p = pb.start();

// Move STDOUT to the output stream (or original code to save as String)
try(var stdo = p.getInputStream()) {
    stdo.transferTo(stdout);
}

int rc = p.waitFor();