14

I'm working on a website conversion. The files as they were linked and served from the web server were case insensitive. But, I've made a dump of the site on my linux system and I'm writing scripts to migrate data. The problem is that I'm running into case sensitivity problems between link strings in the pages and the actual word case on the file system.

For instance, a page might have a link like <a href='/subfolder/PageName.asp'> while the actual file is /subfolder/pagename.asp. Likewise with images — <img src='spacer_sm.gif'> might be Spacer_Sm.gif.

So my thought is to change all directory and filenames to their lower-case equivalents for the site download. How do I do this (and might there be a better way?)

Even if there are unix commands that have case-insensitve switches, I'm using php, so not all of the filesystem commands there have options for case sensitivity.

user394
  • 14,404
  • 21
  • 67
  • 93

4 Answers4

9

Zsh

zmv -o-i '(**/)(*)' '$1${2:l}'

Explanations: zmv renames files matching a pattern according to the given replacement text. -o-i passes the -i option to each mv command under the hood (see below). In the replacement text, $1, $2, etc, are the successive parenthesized groups in the pattern. ** means all (sub)*directories, recursively. The final (/) is not a parenthesized group but a glob qualifier meaning to match only directories. ${2:l} converts $2 to lowercase.

Perl rename

Here I use the Perl rename script that Debian and Ubuntu ship as /usr/bin/prename (typically available as rename as well). With bash ≥4 or zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' **/*

With other shells:

find . -depth -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +

Portable

Recursively:

find . -depth -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

The use of -depth ensures that deeply nested directories are processed before their ancestors.

8

I don't know whether your unix-flavor has a rename. Many Linuxes have, and it is part of a perl-package, if you search for a repository.

find ./ -depth -exec rename -n 'y/[A-Z]/[a-z]/' {} ";"

Above version with

rename -n 

doesn't really perform the action, but only print what would be done. You omit the -n to do it for real.

user unknown
  • 10,482
  • What 'language' or regex is the 'y/[A-Z]/[a-z]/' part? – user394 Sep 07 '11 at 15:57
  • Well, since rename is part of a perl package, I guess perl, but the pattern is used in sed too, and maybe in AWK as well. I only know sed quiet well. I translate y to translate or map, but I don't know where the character origins from. – user unknown Sep 07 '11 at 16:21
  • Must be perl regex - Gilles in his answer says rename is a perl script. – user394 Sep 07 '11 at 16:26
  • Yes, and you may use perl regexs, to modify the filenames, which doesn't necessarily conclude from being written in perl, but which might be the more interesting question. – user unknown Sep 07 '11 at 16:33
1

It did not work on the following directory structure :

JKL/
deF/
ABC/DEf
ABC/gHi
ghi/jkL

Here's an example that does work :

for i in `find | sort -r | sed '$d'`; do \
   b=${i%/*}; e=${i##*/}; mv $i $b'/'${e,,}; done

For an explanation on b and e vars:

man bash

Then use the following key sequence: /,,Enterbb

slm
  • 369,824
0

The accepted answer didn't work for me as it tried to change all the directories at once. I found another solution on stackexchange very similar to the portable one from Gilles above: from Baramin -
https://stackoverflow.com/questions/4268591/unix-rename-files-directories-to-uppercase

I've copied it here:

find . -depth | \
while read LONG; do
   SHORT=$( basename "$LONG" | tr '[:lower:]' '[:upper:]' )
   DIR=$( dirname "$LONG" )
   if [ "${LONG}" != "${DIR}/${SHORT}"  ]; then
     mv "${LONG}" "${DIR}/${SHORT}"
   fi
done

To which I changed the tr command to i.e: sed s/cat/dog/g

Any thanks goes to Baramin at link above.i.e.

JJones
  • 256