2

For example, I want to check if a directory exists on the phone.

R=$(adb shell 'ls /mnt/; echo $?' | tail -1);

$ echo $R
0

$ if [ "$R" -ne 0 ]; then echo "Path doesn't exist"; else echo "Path exists"; fi
: integer expression expected
Path exists

What's wrong with R? Ok, try it with another variable which is definitely 0.

$ x=0
$ if [ "$x" -ne 0 ]; then echo "Path doesn't exist"; else echo "Path exists"; fi

Path exists

$ echo "|$x|"
|0|

$ echo "|$R|"
|0

The second pipe isn't printed. Is there a character after 0? Try to trim:

$ R=$(adb shell 'ls /mnt/; echo $?' | tail -1 | xargs)
$ echo "|$R|"
|0

I'm out of ideas.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
ka3ak
  • 1,235
  • 4
  • 18
  • 30

2 Answers2

8

adb is adding a carriage-return (aka 0x0d, Ctrl-M, \r, etc) before the line-feed. Probably for ease of use with Windows software that expects lines to end with CR-LF rather than just LF.

You can see this yourself with hexdump aka hd, e.g.:

$ printf "$R" | hd
00000000  30 0d                                             |0.|
00000002

Because you only need to return a single value (the exit code). you could use printf instead of echo and redirect all of ls's output to /dev/null on the Android device to avoid printing any newlines (then adb doesn't add a CR):

R="$(adb shell 'ls /mnt/ > /dev/null 2>&1 ; printf $?')"

If your android device doesn't have printf, or if you need to return one or more lines of output from a the android shell, you can use tr -d '\r' or dos2unix or sed 's/\r$//' or similar to strip the CR.

dos2unix and sed are better choices than tr here because they will only strip CRs that are immediately followed by LF, leaving alone any CRs that might be in elsewhere in a line:

$ R="$(adb shell 'ls /mnt/ > /dev/null 2>&1 ; echo $?' | dos2unix)"
$ printf "$R" | hd
00000000  30                                                |0|
00000001
cas
  • 1
  • 7
  • 119
  • 185
  • 'printf not found' – ka3ak Aug 17 '17 at 08:29
  • what kind of android device is that? `printf` is even on my ancient HTC Desire HD which I just tested this with (running CM7, not original HTC Android). I'll update with solution for android without printf. – cas Aug 17 '17 at 08:32
  • 1
    btw, `hexdump` aka `hd` is a good tool for diagnosing all sorts of weird 'huh, WTF?' problems like this. It makes it easy to see exactly what input or output you are getting (with hex bytes and ascii representation in `hd`'s default output format) – cas Aug 17 '17 at 08:38
  • Acer Liquid E2 Duo. Bought 2013 or 2014. Your solution with use of 'tr' works. – ka3ak Aug 17 '17 at 08:39
  • my HTC phone is from 2010. but its running CyanogenMod 7, not stock HTC android. Doesn't matter, `tr` will work whether the device has `printf` or not. – cas Aug 17 '17 at 08:41
  • Please use 2> so that there is still one line in case of an error (path doesn't exist). Or it may be still better to use 'tail -1'. – ka3ak Aug 17 '17 at 08:48
  • 1
    The culprit is adb, not echo. Adb adds CR, which is very annoying, for example, when you want to do something like `adb shell tar -cf - …`. – Gilles 'SO- stop being evil' Aug 17 '17 at 23:00
  • I hate android™. So many bad design decisions. So many hours wasted. – eMPee584 Jan 31 '18 at 18:10
0

The other answer does a good job explaining where the asker went wrong. The moral of the story is to be wary of counting characters, since adb might add some.

I wound up doing this

R=$(adb shell 'ls /mnt && echo SUCCESS || echo FAIL' | egrep (SUCCESS|FAIL))
echo $R