How can I rename files only if they don't match a pattern?

Viewed 121

I want to rename files by appending "-renamed" to the basename before the extension, but I also don't want to rename files that already have the "-renamed" string.

For example,

IMG_1234.jpg -> IMG_1234-renamed.jpg
IMG_1235.mp4 -> IMG_1235-renamed.mp4
IMG_1236-renamed.jpg -> no change

For the first part, I have the following working:

for f in *.jpg; do mv $f ${f%.jpg}-renamed.jpg; done
for f in *.mp4; do mv $f ${f%.mp4}-renamed.mp4; done

How can I assure that subsequent runs won't create keep adding the string over and over?

IMG_1234-renamed.jpg -> IMG_1234-renamed-renamed.jpg
IMG_1235-renamed.mp4 -> IMG_1235-renamed-renamed.mp4
1 Answers

Use extended globbing:

#!/bin/bash
shopt -s extglob
for f in !(*-renamed).@(jpg|mp4) ; do
    new=${f%.*}
    new+=-renamed.${f##*.}
    if [[ -e $new ]] ; then
        echo Skipped: "$new" already exists. >&2
    else
        mv "$f" "$new"
    fi
done
  • !(*-renamed) will match anything that doesn't end in -renamed;
  • @(jpg|mp4) matches jpg or mp4;
  • ${f##*.} returns the extension (even if the basename contains several dots).
  • Also, quote your variables so the script works for file names containing whitespace.
  • Moreover, check for the existence of the target file so you don't accidentally overwrite a previously renamed file.
Related