Defina a data de modificação do arquivo a partir da data armazenada como nome do arquivo

0

Eu tenho muitos arquivos em que filename contém a data de criação do arquivo ( IMG_RRRRMMDD_hhmmss.jpg ):

IMG_20171015_133516.jpg
IMG_20171015_133827.jpg
IMG_20171015_142634.jpg
IMG_20171015_142834.jpg
IMG_20171015_142857.jpg

mas a data de criação real do arquivo é diferente. Eu preciso configurá-lo para voltar a data de um nome de arquivo.

Eu sei como alterar a data de todos os arquivos para a data atual:

find -type f -exec touch {} \;

e como analisar o nome do arquivo para obter a data no formato adequado para touch -t

echo IMG_20171015_133516.jpg | awk -F_ '{print $2 substr($3,0,4) "." substr($3,5,2)}'
201710151335.16

Mas não tenho ideia de como combinar esses comandos para alterar todos os arquivos.

find -type f -exec touch -t"$(echo '{}' | awk -F_ '{print $2 substr($3,0,4) "." substr($3,5,2)}')" {} \;

retorna

touch: invalid date format ‘.’

    
por mx0 07.12.2017 / 21:01

1 resposta

5

No shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc têm a expansão ${var:n:m} de substring e, se você precisar recursivamente, ative globstar e use **/IMG_*.jpg .

Fazer isso com find também precisa do shell:

$ find -name "IMG_*.jpg" -exec bash -c '
  for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
  ' sh {} \+

O primeiro argumento para Bash depois do script vai para a variável $0 , que geralmente contém o nome do shell. O restante vai para os parâmetros posicionais $1 , $2 , etc. e for f ou for f in "$@" faz um loop sobre eles. A construção aqui é bastante comum (pelo menos nas respostas unix.SE). A parte principal do loop aqui é a mesma do primeiro exemplo.

O comando find em sua pergunta find .. -exec touch -t"$(...)" {} \; não funciona, pois a substituição do comando está entre aspas duplas, portanto, ele é expandido antes que find seja executado. O {} é canalizado literalmente para awk e acontece que o script awk imprime apenas um ponto.

Se você colocar a substituição do comando em cotações simples , ela será passada para touch as-is ( find só substituiria {} ). touch obteria o argumento -t$(echo ...) , cifrões, parênteses e tudo. find não executa o comando através do shell por si só, precisamos explicitamente fazê-lo, como acima.

No exemplo de aspas simples:

$ find -name x -exec echo 'hello $(foo {})' \;
hello $(foo ./x)
    
por 07.12.2017 / 21:16