Rename file in Mac OS Terminal using Regex or translate from Windows Script
I would like help with a shell script for macOS to rename files with a certain pattern. The script would handle only one file, not multiple.
Here are three examples:
a. Public Talks_ (189) Walking With God Brings Blessings Now and Forever — Chris Ruscher 10_28_2023.mp3
would become
189 – Walking With God Brings Blessings Now and Forever – Chris Ruscher – 2023-10-28-0900.mp3
b. Public Talks_ (55) How Can You Make a Good Name With God? — Gregory Duhon 11_4_2023.mp3
would become
055 – How Can You Make a Good Name With God? – Gregory Duhon – 2023-11-04-0900.mp3
c. Public Talks_ (9) Walking With God Brings Blessings Now and Forever — Chris Ruscher 10_28_2023.mp3
would become
009 – Walking With God Brings Blessings Now and Forever – Chris Ruscher – 2023-10-28-0900.mp3
So in essence, the final format and order should be: track number
, title
, speaker name
, and timestamp
.
- drop the prefix “Public Talks_ “
- Isolate the track number as a 3 digit number with leading zeros as needed
- Dashes in between all 4 elements
- Reformat date to a timestamp like yyyy-mm-dd-0900
I would then take the shell script and use it per file in this dialog box (no need to iterate):
Please note the variable for the file being passed on to the shell script needs to be written as "$1" as seen in the dialog box below.
Someone helped me create one but it only works for Windows and doesn’t take into account "$1" as the file and is set to do multiple files. I need it to work on macOS for one file at a time.
#!/bin/bash
for file in *.mp3; do
# Remove "Public Talks_"
newname=${file#"Public Talks_ "}
# Extract the track number and pad with leading zeros
track=$(echo $newname | grep -o -E '([0-9]+)' | tr -d '()' | awk '{printf "%03dn", $0}')
# Remove track number and trailing spaces
newname=$(echo $newname | sed -E 's/([0-9]+)//' | sed 's/^ *//')
# Extract the title and speaker
title=$(echo $newname | awk -F '—' '{print $1}' | sed 's/ *$//')
speaker=$(echo $newname | awk -F '—' '{print $2}' | awk '{print $1, $2}')
# Extract the date and reformat
date=$(echo $newname | grep -o -E '[0-9]+_[0-9]+_[0-9]+' | tr '_' '-' | awk -F- '{print $3"-"$1"-"$2"-0900"}')
# Concatenate all elements with dashes
newname="$track - $title - $speaker - $date.mp3"
# Rename the file
mv "$file" "$newname"
done
Can anyone translate it into the proper macOS syntax or write a shell script that is even more concise?
In zsh, from within the directory that contains those files, you’d run:
autoload -Uz zmv
zmv -n '*_ ((<0-999>))(* )—( * )(<1-12>)_(<1-31>)_(<1900-2100>)(.mp3)'
'${(l[3][0])1} -$2-$3- $6-${(l[2][0])5}-${(l[2][0])4}-0900$7'
Example:
$ autoload -Uz zmv
$ zmv -n '*_ ((<0-999>))(* )—( * )(<1-12>)_(<1-31>)_(<1900-2100>)(.mp3)'
'${(l[3][0])1} -$2-$3- $6-${(l[2][0])5}-${(l[2][0])4}-0900$7'
mv -- 'Public Talks_ (189) Walking With God Brings Blessings Now and Forever — Chris Ruscher 10_28_2023.mp3' '189 - Walking With God Brings Blessings Now and Forever - Chris Ruscher - 2023-28-10-0900.mp3'
mv -- 'Public Talks_ (55) How Can You Make a Good Name With God? — Gregory Duhon 11_4_2023.mp3' '055 - How Can You Make a Good Name With God? - Gregory Duhon - 2023-4-11-0900.mp3'
mv -- 'Public Talks_ (9) Walking With God Brings Blessings Now and Forever — Chris Ruscher 10_28_2023.mp3' '009 - Walking With God Brings Blessings Now and Forever - Chris Ruscher - 2023-28-10-0900.mp3'
Remove the -n
(dry-run) if happy.
If that has to be a shell script that takes the file names as arguments:
#! /bin/zsh -
set -o extendedglob
pattern='(#b)*_ ((<0-999>))(* )—( * )(<1-12>)_(<1-31>)_(<1900-2100>)(.mp3)'
ret=0
for file {
if [[ $file = $~pattern ]] {
argv=( "$match[@]" )
mv -i -- $file "${(l[3][0])1} -$2-$3- $6-${(l[2][0])5}-${(l[2][0])4}-0900$7" || ret=$?
} else {
print -ru2 "Skipping $file which doesn't match the pattern"
}
}
exit $ret
But you’d be missing on the extra safeguards of zmv
.
Note that we’re looping over all the arguments of the script instead of just processing the first ($1
).