StonedStudio
StonedStudio

Reputation: 537

Replace first character of file in folder from Uppercase to Lower case

I'm trying to convert 3,000 or so .svg files from CapitalCase to camelCase.

Current:

-Folder
--FileName1
--FileName2
--FileName3

Goal:

-Folder
--fileName1
--fileName2
--fileName3

How can I use terminal to change the casing on the first character with to lowercase?

Currently I've been trying something along these lines: for f in *.svg; do mv -v "$f" "${f:1}"; done

All files in the folder start with a letter or number.

Upvotes: 1

Views: 1229

Answers (2)

Gairfowl
Gairfowl

Reputation: 2981

This can be done very succinctly in zsh with zmv:

autoload zmv
zmv -nvQ '(**/)(?)(*.svg)(.)' '$1${(L)2}$3'

This will recurse through any number of directory levels, and can handle name collisions and other edge cases. Some of the pieces:

  • -n: no execution. With this option, zmv will only report what changes it would make. It's a dry run that can be used to test out the patterns.
    Remove the -n when you're ready to actually change the names.
  • -v: verbose.
  • -Q: qualifiers. Indicates that the source pattern has a glob qualifier (in our case (.)).
  • '(**/)(?)(*.svg)(.)': source pattern. This is simply a regular zsh glob pattern, divided into groups with parentheses. The underlying pattern is **/?*.svg(.). The pieces:
    • (**/): directories and subdirectories. This will match any number of directory levels (to only affect the current directory, see below).
    • (?): matches a single character at the start of the file name. We'll convert this to lowercase later.
    • (*.svg): matches the rest of the file name.
    • (.): regular files only. This is a zsh glob qualifier; zmv recognizes it as a qualifier instead of a grouping because of the -Q option. The . qualifier limits the matching to regular files so that we don't try to rename directories.
  • '$1${(L)2}$3': destination pattern. Each of the groupings in the source pattern is referenced in order with $1, $2, etc.
    • $1: the directory. This could contain multiple levels.
    • ${(L)2}: The first letter in the file name, converted to lowercase. This uses the L parameter expansion flag to change the case.
      The l expansion modifier will also work: $2:l.
      The conversion can handle non-ASCII characters, e.g. Éxito would become éxito.
    • $3: the rest of the file name, including the extension.

Variations

This will only change files in the current directory:

zmv -nv '(?)(*.svg)' '$1:l$2'

The source pattern in the following version will only match files that start with an uppercase letter. Since the zmv utility won't rename files if the source and destination match, this isn't strictly necessary, but it will be slightly more efficient:

zmv -nvQ '(**/)([[:upper:]])(*.svg)(.)' '$1${(L)2}$3'

More information

Upvotes: 2

Gadzhiev Islam
Gadzhiev Islam

Reputation: 75

Solving in bash, tested and working fine, be careful though with your files you working on.

Renaming files in current directory where this script is (1st arg then'd be .) or provide a path, it's do lower-casing of the first letter, if it was uppercase, and yet nothing if it was a number, argument must be provided:

# 1 argument - folder name
# 2 argument - file extension (.txt, .svg, etc.)
for filename in $(ls "$1" | grep "$2")
do
  firstChar=${filename:0:1}
  restChars=${filename:1}
  if [[ "$firstChar" =~ [A-Z] ]] && ! [[ "$firstChar" =~ [a-z] ]]; then
    toLowerFirstChar=$(echo $firstChar | awk '{print tolower($0)}')
    modifiedFilename="$toLowerFirstChar$restChars"
    mv "$1/$filename" "$1/$modifiedFilename"
  else
    echo "Non-alphabetic or already lowercase"
    # here may do what you want fith files started with numbers in name
  fi
done

Use: bash script.sh Folder .txt

ATTENTION: Now here after running script and renaming, names of some files may coincide and there would be a conflict in this case. Can later fix it and update this script.

Upvotes: 2

Related Questions