I have a bunch of photos and videos from different sources and want to normalize the file names using Terminal. I looked at a bunch of different tools from NameChanger to Automator and Finder itself. NameChanger does not allow more than one action at a time and Finder and Automator won't allow me to set the date format with a format string.

I've been playing around with a few bash functions and found that

stat -f "%Sm" -t "%Y-%m-%d %H.%M.%S" file.ext

produces the date time format I'm after.

Yet I found that

for file in *.*
    mv "$file" echo stat -f "%Sm" -t "%Y-%m-%d %H.%M.%S" "$file"


-bash: syntax error near unexpected token `done'

I'm not really proficient with bash scripting so excuse any incompetence in the examples above.

What I want to do is remove all of the base name of the file (everything before .jpg) and replace it with the date and time format I got from stat earlier.

For example:

20160708_151344000_iOS.jpg   --> 2016-07-08 15.13.44.jpg
WP_20140915_02_03_15_Raw.jpg --> 2014-09-15 02.03.15.jpg

How do I need to do this?

  • Do you want the moved filename to be created from the result of the stat command in your OP, or from information within the filename itself? Jul 1, 2017 at 15:21
  • I want to read the date value of the file from the file system and use that as the file name instead. After I posted the question though, I noticed that the file system date, EXIF date and the date that already is in the file name (non-normalized) differ from each other for some files. But being able to do the rename from the file system date alone is useful to me nonetheless in case I only have the command line to work with. Jul 1, 2017 at 15:25
  • Are you sure you really want *.*? In DOS this matches all files but in Bash (and generally all Unix shells) it matches all file names which contain a literal dot.
    – tripleee
    Jul 4, 2017 at 5:00
  • Good point but how do I need to rephrase that condition of the loop so everything after the dot is a file name extension? Jul 4, 2017 at 5:18

2 Answers 2

for f in *.*; do 
    echo mv "$f" "$(stat -f '%Sm' -t '%Y-%m-%d %H.%M.%S' "$f").${f##*.}"

Or as a one-liner:

for f in *.*; do echo mv "$f" "$(stat -f '%Sm' -t '%Y-%m-%d %H.%M.%S' "$f").${f##*.}"; done

In either case, remove the echo command after testing.

The ${f##*.} portion of the command get the extension of $f so you can use the glob *.* vs. using an extension in the for f in, i.e. for f in *.* vs. for f in *.jpg

for f in *.jpg; do
    echo mv "$f" "$(stat -f '%Sm' -t '%Y-%m-%d %H.%M.%S' "$f")".jpg

Remove the echo once you are sure that the command looks ok.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .