Reputation: 537
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
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.-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.l
expansion modifier will also work: $2:l
.É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
zmv
documentation:zsh
parameter expansion flags:zsh
notes, including a bunch of zmv
examples:Upvotes: 2
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