-2

I'm trying to do a pipe operation on my Android device through adb (this is for an automated script).

The operation is to fetch the most recently modified file in a particular directory and then delete it.

Let us say this file is file.txt and it is in /sdcard/Android/data/my.app.package on the Android device.

When I try to do adb shell ls -t /sdcard/Android/data/my.app.package | head -1 | xargs rm -f it throws the error:

rm: file.txt: No such file or directory

This is because it expects the full path.

So then I tried ls -t /sdcard/Android/data/my.app.package | head -1 | xargs ls -d | xargs rm -f but it complains with the same error.

Perhaps I need to pass in the $PWD along with the file name to xargs. How can I do that, or is there a better way to do this?

Edit: I have now tried ls -t sdcard/Android/data/my.app.package | head -1 | xargs -I '{}' ls sdcard/Android/data/my.app.package/'{}' and while a similar command works correctly on the Linux system as expected, it does weird stuff on the Android device. Possibly some missing implementation of xargs on Android stack.

nj2237
  • 1,220
  • 3
  • 21
  • 25
  • Quoting `ls -t /sdcard/Android/data/my.app.package | head -1 | xargs rm -f` should work with APT 23 and higher. – oguz ismail Sep 30 '21 at 07:44
  • Putting in quotes doesn't work @oguzismail – nj2237 Sep 30 '21 at 07:50
  • It's a _similar_ question (your problem is that you're running the `rm` on your computer, not on the phone), but I agree it's a poor duplicate, because the solution is different. Voting to reopen. – Ryan M Sep 30 '21 at 09:27
  • The basic problem was already identified by @ogusismail; `ls -t` on a directory does not include the directory name, so you end up running `rm` on a file in the current directory instead of the directory you examined. The real solution is to [never use `ls` in scripts](https://mywiki.wooledge.org/ParsingLs) but the immediate problem here is that you need to quote commands to `adb shell` if you don't want the local shell to evaluate them, which is what the duplicate explained (and your earlier question also was an example of). – tripleee Sep 30 '21 at 09:33

2 Answers2

2

A command like

adb shell foo | bar

runs foo in adb shell, and has your local shell run bar and receive its input from adb shell. If bar should run in adb shell too, you want to pass the entire pipeline to adb shell:

adb shell 'foo | bar'

This part of your question is basically a duplicate of How to type adb shell commands in one line?

Separately, your ls -t command is flawed in several ways. Generally, don't use ls in scripts; but the trivial fix is to run the command in that directory directly. Then you don't need to add the path back on:

adb shell 'cd /sdcard/Android/data/my.app.package &&
           ls -t | head -1 | xargs rm -f'

This still suffers from the various vagaries of parsing ls output; probably a better solution is to use find instead. If you have the facilities of GNU find and related utilities available on the remote device, try

adb shell 'find /sdcard/Android/data/my.app.package -printf "%T@ %p\\0" |
           sort -r -z -n | head -z -n 1 | sed "s/^[^ ]* //" | xargs -0 rm'

(Adapted from https://stackoverflow.com/a/299911/874188 with quoting fixes to allow the overall command to be run inside single quotes.)

If adb shell does not provide access to GNU userspace tools, perhaps just make sure you have very detailed control over what files can land in your directory so that you can reasonably reliably parse the output from ls; or if you can't guarantee that, try hacking something in e.g. Perl.

It is unfortunate that there is no simple standard way to get the oldest or newest n files from a directory in a robust, machine-readable form. It would be nice if there was a more succinct way than these arguably complex and slightly advanced tricks with find.

tripleee
  • 175,061
  • 34
  • 275
  • 318
0

This is the solution that works:

adb shell ls /sdcard/Android/data/my.app.package/`adb shell ls -t /sdcard/Android/data/my.app.package | head -1` | adb shell xargs rm -f
nj2237
  • 1,220
  • 3
  • 21
  • 25
  • This is a crazy workaround for just quoting the script. Your original script had a bug which complicated things slightly but this is in some ways worse. – tripleee Sep 30 '21 at 12:36
  • Could you point out what the bug is and maybe post a solution? I don't prefer to use this crazy workaround either but I cannot find anything else that works. – nj2237 Sep 30 '21 at 12:41