Formatação estranha de data no script bash

Formatação estranha de data no script bash

Estou trabalhando em um script para classificar minha pasta de downloads pela data em que os arquivos foram criados. Este é o script que estou usando:

#!/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 -

O nome da pasta criada por este script é exatamente Juno que me leva a acreditar que há algum tipo de conversão acontecendo em algum lugar.

Se eu fizer apenas um

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

a data aparece 19062014corretamente.

Este é o resultado de um bash -xscript:

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

A funcionalidade que procuro é que o script mova os arquivos para pastas chamadas 19_06_2014etc. 20_06_2014com base em quando o arquivo foi criado.

Responder1

Eu sugeriria usar um formato de data como 2014-06-19. Dessa forma, lsos mostraria em ordem cronológica.

Em um sistema GNU:

#! /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

Com zshem qualquer sistema:

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

cd ~/Downloads &&
  for file (./*(ND.)) {
    zstat -A date -F %F +mtime $file &&
      mkdir -p $date &&
      mv $file $date
  }

Responder2

Suposição: você tem um alias lsque está sendo usado quando você tenta o comando interativamente e esse alias não é usado no script. Algo assim, talvez?

alias ls="ls --full-time"

Observe que a sabedoria convencional diz que tentar analisar lsé uma má ideia. Supondo que você esteja em uma máquina Linux, algo assim pode ser preferível:

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

EDIT: Ou, como Stéphane aponta abaixo, usar findwith -printfé ainda melhor. A saída de staté um pouco mais fácil de prever do que de ls, mas -printfpermite um formato de saída totalmente controlado por você.

Responder3

Aqui está o código completo

#!/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 -

informação relacionada