Using Linux Mint 13, I have been trying to ADB copy files and directories to a connected Android over USB. Need to preserve the timestamps.

(I am aware that in Unix, only Time Modified is stored).

Got a command from Googling but don't understand it much. Link is below. https://android.stackexchange.com/questions/35580/how-can-i-transfer-photos-to-my-android-jelly-bean-device-while-preserving-the-o

After adb push "FROM" "ANDROID_PHONE" I use the command below:

find . | while read file; do timestamp_stat=$(stat -c "%y" "$file"); timestamp=$(date +"%Y%m%d.%H%M%S" -d "$timestamp_stat"); echo "$timestamp: $file"; adb shell su -c "touch -t $timestamp \"/sdcard/ANDROID_PHONE\""; done

I realise that the above command only manages to use Touch to copy timestamps for filenames and directories with no spaces in them. Get error messages eg. Unknown id: R for those with spaces.

How should I amend the code?

  • If you use the file="$(line)" instead of read file, then "$file" will contain any leading or trailing spaces (or other characters, apart from new-lines). If you don't have line, you can use the equivalent head -n 1. But should you not have "$file" in the adb call? – AFH May 8 '15 at 10:55
  • Glanced through the above.. still can't get it to work. Tried find . -print0 | while read file; I guess I don't know enough Linux commands to troubleshoot this.. – blue.grux May 8 '15 at 14:56
  • I think the problem may be double expansion: your host expands once, and the adb shell expands again. I still don't see how the adb command is supposed to know which file the touch command is supposed to act on; or is there something special about the string ANDROID_PHONE? In the past I have mounted the Android as a USB drive, and I have used the normal copy (cp --preserve=all) to maintain the time stamps without resorting to adb. I now use a file management app in the Android to copy over WiFi, and this also preserves them. – AFH May 8 '15 at 16:13
  • Hi AFH, thank you for the reply. The issue is that timestamps for files are preserved, but timestamps for directories is not, thus necessitating use of a script/command to "copy over" timestamps. This script works perfectly for folders or filenames without spaces. I run it from Linux from start of the folder tree I want to compare, and only need to edit the "/sdcard/Download/$file\" part to reflect the Android path I want to compare with. Mounting an Android as a USB drive requires USB Mass Storage which newer phones no longer have. – blue.grux May 8 '15 at 19:05
  • If the touch command on the Android should be touch -t $timestamp "/sdcard/ANDROID_PHONE/$file" then I can see that the problem is double expansion, but without "$file" then I can't follow how it's supposed to work. In passing, I would note that it is unusual to modify directory time-stamps, because they are updated every time an included file or subdirectory is created, deleted or renamed. – AFH May 8 '15 at 21:50

I can explain part of it:

find . is used to list all files and directories in the current path (that is the dot). Find is not told to do anything with the results, but the default behaviour on most find implementations is to print them to std out.

Proper coding would have used a find /path/to/pictures -ls or -print0. The last is useful when there are non standard characters in the name (e.g. spaces).

The output us the previous command is then forwared to the next part. This is done via the pipe (|) symbol.

The next command is wrapped in a while loop (highlighted in bold)

while read file; do timestamp_stat=$(stat -c "%y" "$file"); timestamp=$(date +"%Y%m%d.%H%M%S" -d "$timestamp_stat"); echo "$timestamp: $file"; adb shell su -c "touch -t $timestamp \"/sdcard/ANDROID_PHONE\""; done

This reads from a file (on in our case from stdin which contains the output of the previous command. The results from reading are stored in a variable named file.

(finds -> find's output | --> input for the while loop)

For each of these results the following set of commands is executed in sequence:

timestamp_stat=$(stat -c "%y" "$file");
timestamp=$(date +"%Y%m%d.%H%M%S" -d "$timestamp_stat"); 
echo "$timestamp: $file"; 
adb shell su -c "touch -t $timestamp \"/sdcard/ANDROID_PHONE\""; 

A variable timestamp created and filled with the results from stat -c
(stat is an utility displays information about the file pointed to by file. In this case the file it points to is stored in $file and wrapped in quoted to avoid problems with spaces.

The results are then replaced by the same information in a different format.

Next this result is echo'd to std out. This is probably so the user has some idea where the script is.

Lastly it does something with abd, with which I have no solid information. I guess is instructs the android phone to touch a file. Touching a file usually changes the date on a file to the current time. However in this case it specifies which time to set the file.

From the touch manpage:

-t      Change the access and modification times to the specified time
        instead of the current time of day.  The argument is of the form
         ``[[CC]YY]MMDDhhmm[.SS]'' where each pair of letters represents
         the following:

Moving on to a solution:

Sadly non here, just hints:

  • Change IFS
  • Or use -print0 (and possible with xargs -0)
  • Use move the enteire thing into find. Right now find is used to find the files and the results (including spaces) is then passed on to a shell. Find can do things on its own though. No while readfile is needed. a find /path/to/files -exec "something" {} \; might work better and faster.
  • find <path> -exec <something> {} \; is in many cases actually slower. That's because it will start <something> on every iteration. Many tools can take an arbitrary number of input files, in which case doing files=$(find <path> -print) && <something> $files is faster because it only starts <something> once. – Gx1sptDTDa May 8 '15 at 10:57
  • True. Sometimes you can work around that by find \+. – Hennes May 8 '15 at 11: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.