[android] How to copy and edit files in Android shell?

The Android shell does not have the cp command. Android shell also has no sed or grep or vi. I have no adb daemon available. There is mv command but it rejects to work if source is on a read-only device.

  1. What to do if I have to copy some directories from read-only device recursively?
  2. How to change a line in a text file (e.g. "PATH=/cache" to be "PATH=/mnt/asec") ?

This question is related to android linux shell android-ndk sh

The answer is


You can do it without root permissions:

cat srcfile > /mnt/sdcard/dstfile

Since the permission policy on my device is a bit paranoid (cannot adb pull application data), I wrote a script to copy files recursively.

Note: this recursive file/folder copy script is intended for Android!

copy-r:

#! /system/bin/sh

src="$1"
dst="$2"
dir0=`pwd`

myfind() {
    local fpath=$1

    if [ -e "$fpath" ]
    then
    echo $fpath
    if [ -d "$fpath" ]
    then
        for fn in $fpath/*
        do
            myfind $fn
        done
    fi
    else
    : echo "$fpath not found"
    fi
}


if [ ! -z "$dst" ]
then
    if [ -d "$src" ]
    then
    echo 'the source is a directory'

    mkdir -p $dst

    if [[ "$dst" = /* ]]
    then
        : # Absolute path
    else
        # Relative path
        dst=`pwd`/$dst
    fi

    cd $src
    echo "COPYING files and directories from `pwd`"
    for fn in $(myfind .)
    do
        if [ -d $fn ]
        then
            echo "DIR  $dst/$fn"
            mkdir -p $dst/$fn
        else
            echo "FILE $dst/$fn"
            cat $fn >$dst/$fn
        fi
    done
    echo "DONE"
    cd $dir0

    elif [ -f "$src" ]
    then
    echo 'the source is a file'
    srcn="${src##*/}"
    if [ -z "$srcn" ]
    then
        srcn="$src"
    fi

    if [[ "$dst" = */ ]]
    then
        mkdir -p $dst
        echo "copying $src" '->' "$dst/$srcn"
        cat $src >$dst/$srcn
    elif [ -d "$dst" ]
    then
        echo "copying $src" '->' "$dst/$srcn"
        cat $src >$dst/$srcn
    else
        dstdir=${dst%/*}
        if [ ! -z "$dstdir" ]
        then
            mkdir -p $dstdir
        fi
        echo "copying $src" '->' "$dst"
        cat $src >$dst
    fi
    else
    echo "$src is neither a file nor a directory"
    fi
else
    echo "Use: copy-r src-dir dst-dir"
    echo "Use: copy-r src-file existing-dst-dir"
    echo "Use: copy-r src-file dst-dir/"
    echo "Use: copy-r src-file dst-file"
fi

Here I provide the source of a lightweight find for Android because on some devices this utility is missing. Instead of myfind one can use find, if it is defined on the device.

Installation:

$ adb push copy-r /sdcard/

Running within adb shell (rooted):

# . /sdcard/copy-r files/ /sdcard/files3 

or

# source /sdcard/copy-r files/ /sdcard/files3 

(The hash # above is the su prompt, while . is the command that causes the shell to run the specified file, almost the same as source).

After copying, I can adb pull the files from the sd-card.

Writing files to the app directory was trickier, I tried to set r/w permissions on files and its subdirectories, it did not work (well, it allowed me to read, but not write, which is strange), so I had to do:

        String[] cmdline = { "sh", "-c", "source /sdcard/copy-r /sdcard/files4 /data/data/com.example.myapp/files" }; 
        try {
            Runtime.getRuntime().exec(cmdline);
        } catch (IOException e) {
            e.printStackTrace();
        }

in the application's onCreate().

PS just in case someone needs the code to unprotect application's directories to enable adb shell access on a non-rooted phone,

        setRW(appContext.getFilesDir().getParentFile());

    public static void setRW(File... files) {
        for (File file : files) {
            if (file.isDirectory()) {
                setRW(file.listFiles()); // Calls same method again.
            } else {
            }
            file.setReadable(true, false);
            file.setWritable(true, false);
        }
    }

although for some unknown reason I could read but not write.


Android supports the dd command.

dd if=/path/file of=/path/file

I tried following on mac.

  1. Launch Terminal and move to folder where adb is located. On Mac, usually at /Library/Android/sdk/platform-tools.
  2. Connect device now with developer mode on and check device status with command ./adb status. "./" is to be prefixed with "adb".
  3. Now we may need know destination folder location in our device. You can check this with adb shell. Use command ./adb shell to enter an adb shell. Now we have access to device's folder using shell.
  4. You may list out all folders using command ls -la.
  5. Usually we find a folder /sdcard within our device.(You can choose any folder here.) Suppose my destination is /sdcard/3233-3453/DCIM/Videos and source is ~/Documents/Videos/film.mp4
  6. Now we can exit adb shell to access filesystem on our machine. Command: ./adb exit
  7. Now ./adb push [source location] [destination location]
    i.e. ./adb push ~/Documents/Videos/film.mp4 /sdcard/3233-3453/DCIM/Videos
  8. Voila.

If you just want to append to a file, e.g. to add some lines to a configuration file, inbuilt shell commands are enough:

adb shell
cat >> /path/to/file <<EOF
some text to append
a second line of text to append
EOF
exit

In the above, replace /path/to/file with the file you want to edit. You'll need to have write permission on the file, which implies root access if you're editing a system file. Secondly, replace some text to append and a second line of text to append with the lines you want to add.


If you have root access install busybox (google for instructions).


I could suggest just install Terminal-ide on you device which available in play market. Its free, does not require root and provide convenient *nix environment like cp, find, du, mc and many other utilities which installed in binary form by one button tap.


You can use cat > filename to use standart input to write to the file. At the end you have to put EOF CTRL+D.


To copy dirs, it seems you can use adb pull <remote> <local> if you want to copy file/dir from device, and adb push <local> <remote> to copy file/dir to device. Alternatively, just to copy a file, you can use a simple trick: cat source_file > dest_file. Note that this does not work for user-inaccessible paths.

To edit files, I have not found a simple solution, just some possible workarounds. Try this, it seems you can (after the setup) use it to edit files like busybox vi <filename>. Nano seems to be possible to use too.


Also if the goal is only to access the files on the phone. There is a File Explorer that is accessible from the Eclipse DDMS perspective. It lets you copy file from and to the device. So you can always get the file, modify it and put it back on the device. Of course it enables to access only the files that are not read protected.

If you don't see the File Explorer, from the DDMS perspective, go in "Window" -> "Show View" -> "File Explorer".


Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to android-ndk

Running Node.Js on Android [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113] Error: No toolchains found in the NDK toolchains folder for ABI with prefix: llvm System.loadLibrary(...) couldn't find native library in my case How to use su command over adb shell? java.lang.ClassNotFoundException: Didn't find class on path: dexpathlist Android Fatal signal 11 (SIGSEGV) at 0x636f7d89 (code=1). How can it be tracked down? Android studio, gradle and NDK How to use adb pull command? How to compile and run a C/C++ program on the Android system

Examples related to sh

How to run a cron job inside a docker container? I just assigned a variable, but echo $variable shows something else How to run .sh on Windows Command Prompt? Shell Script: How to write a string to file and to stdout on console? How to cat <<EOF >> a file containing code? Assigning the output of a command to a variable What does set -e mean in a bash script? Get specific line from text file using just shell script Printing PDFs from Windows Command Line Ubuntu says "bash: ./program Permission denied"