1

I have bash script in my Android Studio Project under /res/ directory. How can I run this file in my android app by Runtime.getRuntime().exec(path);?

Edit: All code

 try {
            Process process = Runtime.getRuntime().exec("bash -x raw/plik.sh");

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            int read;
            char[] buffer = new char[4096];
            StringBuffer output = new StringBuffer();
            while ((read = reader.read(buffer)) > 0) {
                output.append(buffer, 0, read);
            }
            reader.close();

            Log.d("lab", "Stat: " + output);
        }catch (Exception e){
            Log.d("lab", e.getMessage());
        }

I dont have logs.

lukassz
  • 3,135
  • 7
  • 32
  • 72
  • I've edited my answer with a tested and working solution. Let me know if it works. Please vote up if the answer is helpful. :) – David Heisnam Aug 20 '15 at 17:57

2 Answers2

2

UPDATE: first solution only executes a list of commands in a file in /res/raw/. It's not a real solution.

Look at second part for a complete solution.

InputStream ins = getResources().openRawResource(
            getResources().getIdentifier("my_file_name_without_extension", "raw", getPackageName()));

        BufferedReader r = new BufferedReader(new InputStreamReader(ins));
        StringBuilder total = new StringBuilder();
        String line;
        try {
            while((line = r.readLine()) != null) {
                total.append(line);
                total.append(" ; ");
            }
            total.delete(total.length() - 3, total.length() -1); // Remove delimiter (;) at end
            r.close();
            ins.close();
        } catch(IOException e) {}

        try {
            Process proc = Runtime.getRuntime()
                .exec(new String[] {"sh", "-c", total.toString()});
            proc.waitFor();
        } catch (Exception ex) {
            ex.printStackTrace();
            Log.v("TAG", "exec failed");
        }

I tested the above code with a script file containing only the lines

cp /mnt/sdcard/Folder1/file /mnt/sdcard/Folder2/
cp /mnt/sdcard/Folder1/file1 /mnt/sdcard/Folder2/

in res/raw.

You'll have to remove the shebang and any empty line from your script. Also, I believe you'll have to include each command in a single line, i.e. you can't have a command spread over multiple lines. Or you could just edit the string building part to suit your particular case.

COMPLETE SOLUTION WITH ROOT ACCESS

InputStream is =  getResources().openRawResource(getResources().getIdentifier("script_name_without_extension", "raw", getPackageName()));
boolean copysuccess = false;
// Copy from /res/raw/script.sh to /data/data/com.mycompany.myapp/files/script.sh
// because we need to chmod the script
File file = new File(getFilesDir(), "script.sh");
String scriptPath = file.getAbsolutePath();
if(!file.exists()) {
    try {
        OutputStream output = new FileOutputStream(file);
        byte[] buffer = new byte[4*1024];
        int read;
        while((read = is.read(buffer))!=-1){
            output.write(buffer,0, read);
        }
        copysuccess = true;
        output.flush();
        output.close();
        is.close();
    } catch(Exception e) {
        copysuccess = false;
        // TODO perform cleanup
    }

    // perform chmod now
    if(copysuccess) {
        try {
            Process proc = Runtime.getRuntime()
                .exec(new String[] {"su", "-c", "chmod 755 "+ scriptPath});
            proc.waitFor();
        } catch (Exception e) {
        }
    }
}

// Execute the script now
try {
    Process proc = Runtime.getRuntime()
        .exec(new String[] {scriptPath});
        proc.waitFor();
    } catch (Exception e) {
}
David Heisnam
  • 2,463
  • 1
  • 21
  • 32
  • No, do not work. I found this http://stackoverflow.com/questions/6301493/android-get-path-of-resource It says that it is not possible. – lukassz Aug 20 '15 at 16:26
  • 1
    @lukassz I have another method that I am very sure will work. If you haven't got your answer, let me know. – David Heisnam Aug 20 '15 at 16:30
  • Thanks, I'm starting to test – lukassz Aug 20 '15 at 19:27
  • Approx. I've tested. Unfortunately, the code will only work for commands liner. In my file, I have written functions and the code will not cause them anymore. The same example. I wanted to run my script with parameters, there is no such option. Is there any other way? – lukassz Aug 30 '15 at 10:01
  • 1
    @lukassz My solution works for simple scripts. Unfortunately, I know of no other way except with root access. – David Heisnam Aug 30 '15 at 10:24
  • 1
    @lukassz If you provide root access to your app, you'll be able to do exactly what you're looking to do. – David Heisnam Aug 30 '15 at 10:27
  • Yes, I provide root access. – lukassz Aug 30 '15 at 10:30
  • In that case, how can I do? To run the functions of this file? – lukassz Aug 30 '15 at 10:56
  • 1
    @lukassz I added full solution with root access. Now you can execute any normal bash script. Will require shebang and all this time. – David Heisnam Aug 30 '15 at 11:57
  • 1
    @lukassz Please vote up if you found the answer helpful. – David Heisnam Aug 30 '15 at 12:00
  • Thank you, I have one more question. I sould put three parameter to this scirpt. I do it so `Process proc = Runtime.getRuntime() .exec(scriptPath +" "+imagePath+" yes yes"); proc.waitFor(); //and read output stream` it is correctly? – lukassz Aug 31 '15 at 12:32
  • @lukassz It should be `exec(new String[] {scriptPath, imagePath, "yes", "yes"})` Put all your parameters in the String[] array like this. – David Heisnam Aug 31 '15 at 12:47
  • OK, it works. In the script mounted disk image and it is not working. How to manually enter this command will work. I do not know why. `/system/xbin/busybox mount /storage/sdcard0/debian_chroot/debian.img /mnt/linux` – lukassz Aug 31 '15 at 13:15
  • I have the impression that not all of the command in my script to perform because it calls `/ system / xbin / busybox mount -o remount, rw, exec, dev, suid /` and then I create a folder in the directory / mnt /, but this folder does not create . – lukassz Aug 31 '15 at 13:20
  • @lukassz **line 1** mknod /dev/block/loop255 b 7 255 **line2** losetup /dev/block/loop255 /path/to/image.img **line 3** mount -t ext4 /dev/block/loop255 /mnt/linux To unmount *umount /mnt/linux* – David Heisnam Aug 31 '15 at 13:25
  • @lukassz The script isn't running as root. Use `exec(new String[] {"su", "-c", scriptPath, imagePath, "yes", "yes"})` – David Heisnam Aug 31 '15 at 13:32
  • @lukassz the **mount** command requires root access. That's why it's not working. – David Heisnam Aug 31 '15 at 13:36
  • @lukassz The **Linux Deploy** app is probably the best app for booting a Linux distro on an Android device. It is open source. https://github.com/meefik/linuxdeploy I suggest you study the codes there. I'm sure you'll find all your answer there. – David Heisnam Aug 31 '15 at 13:46
  • I try run script with `su -c` but this way at all do not want to run the script. – lukassz Aug 31 '15 at 14:17
  • @lukassz then try `exec(new String[] {"su", "-c", scriptPath + " " + imagePath + " yes yes"})` If you have any more queries, I'll reply in **Chat** – David Heisnam Aug 31 '15 at 14:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88383/discussion-between-davidh-and-lukassz). – David Heisnam Aug 31 '15 at 14:28
  • The program I work in the end, but now as he ran after a year does not work. In general you do not get from this information from the process... – lukassz Apr 26 '16 at 18:26
  • I get an error: `sh: /data/user/0/lab.linuxservice.com.linuxservice/files/script.sh: No such file or directory` but this file is there... – lukassz Apr 26 '16 at 18:30
0

First I think better place for bash scrip is a /raw directory.

But even raw directory can be wrong because I'm not sure if your app will have a access to this dir - should have but I'm not sure.

Next usefull command is: bash -x raw/script.sh

mariopce
  • 1,116
  • 9
  • 17
  • Yes, I was wrong. I have a file in the raw. But this code `Process process = Runtime.getRuntime().exec("bash -x raw/plik.sh");` is not working. – lukassz Aug 20 '15 at 15:34
  • Runtime.getRuntime().exec() method return Process when you have process you can get input and output stream and check where is a problem. Please check http://stackoverflow.com/questions/14932502/android-logcat-and-bufferedreader-no-logs – mariopce Aug 20 '15 at 15:36
  • Please, look for my question. I woud like print logs but I nothing gets. – lukassz Aug 20 '15 at 15:42