Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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:


cd ~/Downloads
for FILENAME in *
    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" \;
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 -

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
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 '14 at 19:39
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 '14 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"

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 '14 at 21:22

Here's the complete code

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

cd -
share|improve this answer
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 '14 at 19:55

Your Answer


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.