views:

186

answers:

4

I need to do a touch of several files in a directory in reverse alphabetical order, with a 1 second delay. These files have spaces in their names. I've tried this:
ls | sort -r | tr '\012' '\000' | xargs -0 touch

and this:

#!/bin/bash

for i in $(ls -r); 
do
    touch "$i"
    sleep 1
done

but the first makes it too quick and doesn't get what I want (to the files to appear in order in my device), and the second doesn't handle the spaces right.

Any ideas?

Edit: Sorry, forgot to add that it would be great to do this the faster as possible, 'cause if I have to wait 1 second between files, and I have 60+ files, I don't want to wait more than 1 minute. Sorry for the trouble.

+3  A: 

read will read in a line at a time:

ls -r | while read FILE; do
    touch "$FILE"
    sleep 1
done

Alternatively, you could mess around with the $IFS variable so that only newlines separate items in the for i in list syntax, not spaces or tabs:

(IFS=$'\n'
for FILE in $(ls -r); do
    touch "$FILE"
    sleep 1
done)

(Parentheses added so $IFS is restored afterwards. Things'll likely go bananas if you forget and leave it set to a non-standard value.)

By the way, you could also skip the sleeps by using touch -t to set a specific timestamp. That looks to be rather more difficult to do, though, so I'll leave that to a more adventurous responder. :-)

John Kugelman
Interesting, I didn't know about the IFS variable. +1
Adam Rosenfield
+1  A: 

Another bash solution:

#!/bin/bash
OFFSET_IN_SEC=0

# for each file in reverse alphabetic order
for file in (ls -r); do
   # offset in seconds from current time                               
   OFFSET_IN_SEC=$(( $OFFSET_IN_SEC + 1 ))

   # current time + $OFFSET_IN_SEC in format used by touch command
   TOUCH_TIMESTAMP=$(date -d "$OFFSET_IN_SEC sec" +%m%d%H%M.%S)

   # touch me :)
   # NOTE: quotes around $file are for handling spaces
   touch -t $TOUCH_TIMESTAMP "$file"
done
dimba
Move the initial time stamp (date -d) outside of the loop. If the files are on a floppy disk, or across a slow SAMBA share, it could take more than 1 second to touch all 60 files.
Dave Jarvis
A: 

Finally I used this:

#!/bin/bash
(OFFSET_IN_SEC=0
IFS=$'\n'
# for each file in reverse alphabetic order
for file in $(ls -r); do
   # offset in seconds from current time                               
   OFFSET_IN_SEC=$(( $OFFSET_IN_SEC + 1 ))

   # current time + $OFFSET_IN_SEC in format used by touch command
   TOUCH_TIMESTAMP=$(date -d "$OFFSET_IN_SEC sec" +%m%d%H%M.%S)

   # touch me :)
   # NOTE: quotes around $file are for handling spaces
   touch -t $TOUCH_TIMESTAMP "$file"
done)

I've had to include the IFS setting, as the quotes around $file doesn't handle the spaces fine.

Thanks all!!!

nightshadex101
A: 

This works for me:

while read ; do
    [ -d "$REPLY" ] || touch "$REPLY"
    sleep 1
done < <( find . -maxdepth 1  | sort -r )
fgm