3

I'm trying to use $EXTERNAL_STORAGE in the adb pull command. I noticed that the variable has its scope defined in Android only and so it would not work successfully in adb pull $EXTERNAL_STORAGE/Pictures/Screenshots/ ~/.

Of course, I can write an absolute path to fetch all the screenshots but the issue is something else.

I attempted:

af=$(adb shell echo \$EXTERNAL_STORAGE/Pictures/Screenshots/)
adb pull $af ~/

which gives me the error:

' does not existstorage/sdcard0/Pictures/Screenshots/

Alternatively, if I do:

af="/storage/sdcard0/Pictures/Screenshots/"
adb shell $af ~/

then the screenshots gets fetched successfully.

There is a difference in character count. For the first case where $af receives input from adb shell, the output of ${#af} and echo $af | wc -c is 39 and 40 respectively.

For the second case where a direct string is fed into $af, the output of ${#af} and echo $af | wc -c is 38 and 39 respectively.

I thought this may be a result of trailing space, so I added a space in the $af=/storage/sdcard0/Pictures/Screenshots/ " but adb pull $af ~/ still worked well.

Also, I ran echo $af | fold -w1 | wc -l and for both the cases the output is 38.

So, what's causing ADB to throw that error?


If it matters, I'm using Slackware 14.1 and rooted Android 4.2.1 and 5.0.2.

3

You were almost there with your first attempt. The problem is that adb unhelpfully adds a carriage return at the end of every line. You can't see it in the basic usage where the output is printed to the terminal, because a carriage return at the end of a line has no visual effect (the carriage return moves the cursor to the beginning of the current line, but then the newline moves the cursor to the beginning of the next line).

When you store the output in a variable, the carriage return is there in $af, and then adb pull treats it as part of the file name. The error message looks weird because of the carriage return in the middle, which causes the second half of the message to overwrite the first half.

Remove the carriage return before using the variable.

af=$(adb shell 'echo "$EXTERNAL_STORAGE/Pictures/Screenshots/"')
af=${af%$'\r$}
adb pull "$af" ~/

or directly

adb pull "$(adb shell 'echo "$EXTERNAL_STORAGE/Pictures/Screenshots/"' | tr -d '\r')" ~/

or

adb pull "$(adb shell 'echo "$EXTERNAL_STORAGE"' | tr -d '\r')/Pictures/Screenshots/" ~/

Alternatively, declare the carriage return as a word separator, and leave the af variable unquoted. This only works if $af doesn't contain whitespace.

IFS+=$'\r'
adb pull $(adb shell 'echo "$EXTERNAL_STORAGE/Pictures/Screenshots/"') ~/

Alternatively, create a symbolic link with a name of your choice instead of relying on the environment variable.

adb shell 'ln -s "$EXTERNAL_STORAGE" /external-storage'

once and for all, then to copy files

adb pull /external-storage/Pictures/Screenshots ~/

With the symlink, you can avoid the adb command line and use adbfs to mount the Android filesystem.

mkdir -p ~/mnt/android
adbfs ~/mnt/android
cp -Rp ~/mnt/android/Pictures/Screenshots ~/
  • Thank you very much. That does the job well and explains the issue precisely. May I know how did you come to know that ADB was adding that carriage return? Could it be by writing into a file or something? May be such technique can help me to troubleshoot more and perhaps, save me from asking a question at all. – Firelord Aug 27 '15 at 11:40
  • 1
    @Firelord I don't remember how I first found out. I may well have been doing something similar to what you're doing. You can visualize the output by piping the adb command into something like hd, hexdump -C1, xxd -g1, od -tx1, … (ordered from nicest to most portable) – Gilles Aug 27 '15 at 15:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.