3
#!/bin/sh
for f in *.png
do
    echo mv -n "$f" "$(date +%Y%m%d-%H-%M-%S)_$f"
done

I want to rename several files with their timestamp as stated in (ls -lt --full-time), but I run when my code above, the name uses the current date/time or modify time. I want the year, month, and day in yymmdd format.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
qwerty
  • 29

2 Answers2

7

Just use the -r option of GNU date which reports the date corresponding to the last modification time of the file after symlink resolution (like ls -Ll does)

#!/bin/sh -
for f in *.png
do
  t=$(date -r "$f" +%Y%m%d-%H-%M-%S) &&
    echo mv -n -- "$f" "${t}_$f"
done

Or use zsh which has a stat builtin to format the time in any format:

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

for f (*.png(N)) stat -A t -F %Y%m%d-%H-%M-%S +mtime -- $f && print -r mv -n -- $f ${t}_$f

Note that some systems including GNU and BSDs have added (much later¹) their own stat command though with completely different APIs (from zsh's and between each other).

exiftool can also rename any file based on any of its attributes:

exiftool -d %Y%m%d-%H-%M-%S '-FileName<${FileModifyDate}_${FileName}' -- *.png

Note that all those and your ls -lt --full-time (which should probably have an extra -L in case some of those png files are symlinks) look at the last modification time of the file. That can be considered as the creation time of the contents of the file which generally is what you care for. Files on Linux also have what is called a birth time aka creation time which reflects when the file spawned into existence (but has little to do with when the contents was created).

With recent versions of GNU ls with a recent kernel and GNU libc (so not on CentOS), you can retrieve that with ls --time=birth -Ll --full-time, and with recent versions of GNU stat with stat -Lc %w, but none of date, zsh stat nor exiftool can retrieve that as the API to do so is very recent and Linux-specific. And that timestamp is generally not useful. See When was file created or Is there still no Linux kernel interface to get file creation date? for details.


¹ Though note that early Unix versions did have a stat command. For some reason it seemed to have disappeared in the mid-70s as research Unix v6 no longer had one.

4

You should use stat command to get the file date. I don't know if you want to get the creation date (birth) or the modification date of the file. I will provide an example using both dates.

Using birth date

#!/bin/sh
for f in *.png
do
    cdate=$(stat -c '%w'  "$f" | cut -d ' ' -f1)
    echo mv -n "$f" "${cdate}_$f"
done

Using modification date

#!/bin/sh
for f in *.png
do
    mdate=$(stat -c '%y'  "$f" | cut -d ' ' -f1)
    echo mv -n "$f" "${mdate}_$f"
done

With stat -c '%w' somefile you get the creation/birth date and with stat -c '%y' somefile you get the modification date.

The code above will return the date in YYYYMMDD format, if you want to get only in YYMMDD format you can apply parameter expansion (I'm not sure if this one is supported by POSIX or sh). Here you are another example (using bash):

Using birth date

#!/bin/bash
for f in *.png
do
    cdate=$(stat --printf='%.10w\n' "$f")
    echo mv -n "$f" "${cdate#??}_$f"
done

Using modification date

#!/bin/bash
for f in *.png
do
    mdate=$(stat --printf='%.10y\n' "$f")
    echo mv -n "$f" "${mdate#??}_$f"
done

With stat --printf='%.10w\n' or stat --printf='%.10y\n' I'm getting the first ten characters of the string that will represent the date in YYYYMMDD format. With ${cdate#??} or ${mdate#??} I'm removing the first two digits of the date so I will get this one in YYMMDD format.