Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am working on a script to sort my downloads folder by the date the files were created. This is the script I am using:

#!/bin/bash

cd ~/Downloads
for FILENAME in *
do
    if [[ -f $FILENAME ]]; then
        date="$(ls -l $FILENAME | tr -s ' ' | cut -d ' ' -f 6 | tr -d '.')"
        mkdir -vp "$date"
        find . -maxdepth 1 -type f -name $FILENAME -exec mv {} "$date" \;
    fi
done
cd -

The name of the folder created by this script is just Jun which leads me to believe there is some sort of conversion going on somewhere.

If I do just a

ls -l test0 | tr -s ' ' | cut -d ' ' -f 6 | tr -d '.'

the date shows 19062014 correctly.

This is the result of a bash -x of the script:

sigurd@Goliath ~ -> bash -x clean
+ cd /home/sigurd/Downloads
+ for FILENAME in '*'
+ [[ -f test0 ]]
++ ls -l test0
++ tr -s ' '
++ cut -d ' ' -f 6
++ tr -d .
+ date=Jun
+ mkdir -vp Jun
mkdir: created directory 'Jun'
+ find . -maxdepth 1 -type f -name test0 -exec mv '{}' Jun ';'
+ for FILENAME in '*'
+ [[ -f test1 ]]
++ ls -l test1
++ tr -s ' '
++ cut -d ' ' -f 6
++ tr -d .
+ date=Jun
+ mkdir -vp Jun
+ find . -maxdepth 1 -type f -name test1 -exec mv '{}' Jun ';'
+ cd -
/home/sigurd

The functionality I'm looking for is that the script should move files into folders named 19_06_2014, 20_06_2014 etc. based on when the file was created.

share|improve this question

3 Answers 3

up vote 3 down vote accepted

Wild guess: you have an alias for ls that's being used when you try the command interactively, and that alias isn't used in the script. Something like this, perhaps?

alias ls="ls --full-time"

Note that conventional wisdom says that trying to parse ls is a bad idea. Assuming you're on a Linux machine, something like this might be preferable:

stat "$FILENAME" | awk '/^Modify: /{print $2}'

EDIT: Or, as Stéphane points out below, using find with -printf is even better. The output of stat is slightly easier to predict than ls, but -printf allows for an output format that's entirely controlled by you.

share|improve this answer
    
Thanks, I figured it would be easier to use awk, just wasn't quite comfortable as to how. –  slopedoo Jun 19 at 19:39
1  
Parsing the output of stat like that is hardly any better. GNU find can print the modification time in any format you like with its -printf. –  Stéphane Chazelas Jun 19 at 19:57

I would suggest using a date format like 2014-06-19. That way a ls would show them in chronological order.

On a GNU system:

#! /bin/bash -
cd ~/Downloads &&
  find . -maxdepth 1 -type f -printf '%p\0%TF\0' |
    while IFS= read -rd '' file && read -d '' date; do
      mkdir -vp "$date" && mv "$file" "$date"
    done

With zsh on any system:

#! /bin/zsh
zmodload zsh/stat || exit

cd ~/Downloads &&
  for file (./*(ND.)) {
    zstat -A date -F %F +mtime $file &&
      mkdir -p $date &&
      mv $file $date
  }
share|improve this answer
    
Hadn't thought about using -printf instead of stat - that's definitely an improvement. –  godlygeek Jun 19 at 21:22

Here's the complete code

#!/bin/bash
cd ~/Downloads
for FILENAME in $(find . -maxdepth 1 -type f); do    
    DATE=$(stat "$FILENAME" | awk '/^Modify: /{print $2}')
    [ ! -d "$DATE" ] && mkdir -vp "$DATE"

    mv "$FILENAME" "${DATE}/$FILENAME"
done
cd -
share|improve this answer
2  
Note that GNU find (you're already using a GNUism with -maxdepth) can do stat's job (and better) with -printf (find had -printf decades before GNU introduced its stat command). Using command substitution on the output of find means that it will break (possibly severely with security implications) on filenames contain blank or wildcard characters. You're not checking for succesful completion of cd or mkdir. –  Stéphane Chazelas Jun 19 at 19:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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